fix(lamni): sl6 in xray eye, 30nm FZP distance, OSA collision offset
CI for csaxs_bec / test (push) Failing after 3m2s
CI for csaxs_bec / test (push) Failing after 3m2s
- leye_in/leye_out open/restore sl6 in addition to sl1; opening increased to 1.0 mm - lfzp_info and PDF report account for the 30 nm FZP holder placing the chip 11 mm further downstream - commission loptz collision_offset (87.87) and fix the "collide at losaz" printout to subtract loptz - ptycho_lamni config updates from beamtime (eye/flight tube positions, loptz limits, OSA in positions) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LJWYXx4SS8NgFWog81xjyf
This commit is contained in:
1 parent
04bedba60a
commit
51de36130e
3 files changed
+94
-54
No files matched your search
@@ -2756,10 +2756,13 @@ class LamNI(
|
||||
except Exception:
|
||||
focal_distance_str = "N/A"
|
||||
# FZP focus-to-sample distance: same live z-stage-based calculation
|
||||
# lfzp_info() already uses -- not a stored value.
|
||||
# lfzp_info() already uses -- not a stored value. Depends on the
|
||||
# mounted FZP type (30 nm sits in an extra holder further downstream).
|
||||
try:
|
||||
loptz_val = dev.loptz.read()["loptz"]["value"]
|
||||
fzp_sample_distance_str = f"{-loptz_val + 85.6 + 52:.1f}"
|
||||
fzp_sample_distance_str = (
|
||||
f"{self._fzp_sample_distance(loptz_val, fzp_zone_width_nm):.1f}"
|
||||
)
|
||||
except Exception:
|
||||
fzp_sample_distance_str = "N/A"
|
||||
# Sample-to-detector distance: userParameter on loptx, defaults to
|
||||
|
||||
@@ -214,21 +214,65 @@ class LamNIOpticsMixin:
|
||||
return None
|
||||
return param.get(var)
|
||||
|
||||
@property
|
||||
def _sl1xs_before_eye(self):
|
||||
return self.client.get_global_var("lamni_sl1xs_before_eye")
|
||||
# slits opened by _EYE_SLIT_OPENING (relative) while the xray eye is in
|
||||
_EYE_SLITS = ("sl1", "sl6")
|
||||
_EYE_SLIT_OPENING = 1.0 # mm
|
||||
|
||||
@_sl1xs_before_eye.setter
|
||||
def _sl1xs_before_eye(self, val):
|
||||
self.client.set_global_var("lamni_sl1xs_before_eye", val)
|
||||
@staticmethod
|
||||
def _slit_size(name):
|
||||
# sl1xs/sl1ys are EpicsMotors (user_readback), sl6xs/sl6ys are
|
||||
# VirtualSlitWidth pseudo motors (readback)
|
||||
device = dev[name]
|
||||
if hasattr(device, "user_readback"):
|
||||
return device.user_readback.get()
|
||||
return device.readback.get()
|
||||
|
||||
@property
|
||||
def _sl1ys_before_eye(self):
|
||||
return self.client.get_global_var("lamni_sl1ys_before_eye")
|
||||
def _slit_before_eye(self, slit):
|
||||
return (
|
||||
self.client.get_global_var(f"lamni_{slit}xs_before_eye"),
|
||||
self.client.get_global_var(f"lamni_{slit}ys_before_eye"),
|
||||
)
|
||||
|
||||
@_sl1ys_before_eye.setter
|
||||
def _sl1ys_before_eye(self, val):
|
||||
self.client.set_global_var("lamni_sl1ys_before_eye", val)
|
||||
def _set_slit_before_eye(self, slit, xs, ys):
|
||||
self.client.set_global_var(f"lamni_{slit}xs_before_eye", xs)
|
||||
self.client.set_global_var(f"lamni_{slit}ys_before_eye", ys)
|
||||
|
||||
def _open_slits_for_eye(self):
|
||||
for slit in self._EYE_SLITS:
|
||||
xs, ys = f"{slit}xs", f"{slit}ys"
|
||||
if xs not in dev or ys not in dev:
|
||||
continue
|
||||
self._set_slit_before_eye(slit, self._slit_size(xs), self._slit_size(ys))
|
||||
scans.umv(
|
||||
dev[xs], self._EYE_SLIT_OPENING, dev[ys], self._EYE_SLIT_OPENING, relative=True
|
||||
)
|
||||
|
||||
def _restore_slits_after_eye(self):
|
||||
for slit in self._EYE_SLITS:
|
||||
xs, ys = f"{slit}xs", f"{slit}ys"
|
||||
xs_before, ys_before = self._slit_before_eye(slit)
|
||||
if xs_before is None or ys_before is None:
|
||||
continue
|
||||
if xs not in dev or ys not in dev:
|
||||
self._set_slit_before_eye(slit, None, None)
|
||||
continue
|
||||
# if the slit was manually re-adjusted while the eye was in,
|
||||
# offer to keep the current size instead of restoring the
|
||||
# pre-eye value
|
||||
tol = 0.01 # mm (10 microns)
|
||||
manually_adjusted = not np.isclose(
|
||||
self._slit_size(xs), xs_before + self._EYE_SLIT_OPENING, atol=tol
|
||||
) or not np.isclose(self._slit_size(ys), ys_before + self._EYE_SLIT_OPENING, atol=tol)
|
||||
|
||||
if manually_adjusted and self.OMNYTools.yesno(
|
||||
f"{xs}/{ys} appear to have been adjusted manually while the "
|
||||
"eye was in. Keep the current slit size instead of "
|
||||
"restoring the pre-eye value?"
|
||||
):
|
||||
print(f"Keeping current {slit} size, not restoring pre-eye value.")
|
||||
else:
|
||||
umv(dev[xs], xs_before, dev[ys], ys_before)
|
||||
self._set_slit_before_eye(slit, None, None)
|
||||
|
||||
def leye_out(self):
|
||||
self.loptics_in()
|
||||
@@ -240,31 +284,7 @@ class LamNIOpticsMixin:
|
||||
if self.csaxs is not None:
|
||||
self.csaxs.fil_trans(1, print_only=False)
|
||||
|
||||
sl1xs_before = self._sl1xs_before_eye
|
||||
sl1ys_before = self._sl1ys_before_eye
|
||||
if sl1xs_before is not None and sl1ys_before is not None:
|
||||
# if the slit was manually re-adjusted while the eye was in,
|
||||
# offer to keep the current size instead of restoring the
|
||||
# pre-eye value
|
||||
current_sl1xs = dev.sl1xs.user_readback.get()
|
||||
current_sl1ys = dev.sl1ys.user_readback.get()
|
||||
expected_sl1xs = sl1xs_before + 0.3
|
||||
expected_sl1ys = sl1ys_before + 0.3
|
||||
tol = 0.01 # mm (10 microns)
|
||||
manually_adjusted = not np.isclose(
|
||||
current_sl1xs, expected_sl1xs, atol=tol
|
||||
) or not np.isclose(current_sl1ys, expected_sl1ys, atol=tol)
|
||||
|
||||
if manually_adjusted and self.OMNYTools.yesno(
|
||||
"sl1xs/sl1ys appear to have been adjusted manually while the "
|
||||
"eye was in. Keep the current slit size instead of "
|
||||
"restoring the pre-eye value?"
|
||||
):
|
||||
print("Keeping current slit size, not restoring pre-eye value.")
|
||||
else:
|
||||
umv(dev.sl1xs, sl1xs_before, dev.sl1ys, sl1ys_before)
|
||||
self._sl1xs_before_eye = None
|
||||
self._sl1ys_before_eye = None
|
||||
self._restore_slits_after_eye()
|
||||
|
||||
leyey_out = self._get_user_param_safe("leyey", "out")
|
||||
umv(dev.leyey, leyey_out)
|
||||
@@ -318,10 +338,7 @@ class LamNIOpticsMixin:
|
||||
# both already in position -> do nothing
|
||||
pass
|
||||
else:
|
||||
if "sl1xs" in dev and "sl1ys" in dev:
|
||||
self._sl1xs_before_eye = dev.sl1xs.user_readback.get()
|
||||
self._sl1ys_before_eye = dev.sl1ys.user_readback.get()
|
||||
scans.umv(dev.sl1xs, 0.3, dev.sl1ys, 0.3, relative=True)
|
||||
self._open_slits_for_eye()
|
||||
|
||||
if self.csaxs is not None:
|
||||
self.csaxs.fil_trans(0.05, print_only=False)
|
||||
@@ -539,6 +556,17 @@ class LamNIOpticsMixin:
|
||||
else:
|
||||
print("OSA is already at the OUT position.")
|
||||
|
||||
# the 30 nm FZP sits in an additional holder that puts the chip this
|
||||
# much further downstream (closer to the sample) than the 60 nm FZP
|
||||
_FZP_30NM_HOLDER_OFFSET = 11.0 # mm
|
||||
|
||||
def _fzp_sample_distance(self, loptz_val, outermost_zone_width_nm):
|
||||
"""FZP-to-sample distance in mm for the given loptz position and FZP type."""
|
||||
distance = -loptz_val + 85.6 + 52
|
||||
if outermost_zone_width_nm == 30:
|
||||
distance -= self._FZP_30NM_HOLDER_OFFSET
|
||||
return distance
|
||||
|
||||
def lfzp_info(self, mokev_val=-1):
|
||||
if mokev_val == -1:
|
||||
# The energy readback device is "ccm_energy" (same as flomni's
|
||||
@@ -553,8 +581,13 @@ class LamNIOpticsMixin:
|
||||
)
|
||||
return
|
||||
loptz_val = dev.loptz.read()["loptz"]["value"]
|
||||
distance = -loptz_val + 85.6 + 52
|
||||
print(f"The sample is in a distance of {distance:.1f} mm from the FZP.")
|
||||
distance = self._fzp_sample_distance(loptz_val, 60)
|
||||
distance_30nm = self._fzp_sample_distance(loptz_val, 30)
|
||||
print(
|
||||
f"The sample is in a distance of {distance:.1f} mm from a 60 nm FZP and "
|
||||
f"{distance_30nm:.1f} mm from a 30 nm FZP (extra holder, "
|
||||
f"{self._FZP_30NM_HOLDER_OFFSET:.0f} mm further downstream)."
|
||||
)
|
||||
|
||||
print(f"At the current energy of {mokev_val:.4f} keV we have following options:\n")
|
||||
|
||||
@@ -597,7 +630,7 @@ class LamNIOpticsMixin:
|
||||
outermost_zonewidth = 30e-9
|
||||
focal_distance = diameter * outermost_zonewidth / wavelength
|
||||
beam_size = (
|
||||
-diameter / (focal_distance * 1000) * (focal_distance * 1000 - distance) * 1e6
|
||||
-diameter / (focal_distance * 1000) * (focal_distance * 1000 - distance_30nm) * 1e6
|
||||
)
|
||||
table.add_row(
|
||||
f"{diameter*1e6:.2f} microns",
|
||||
@@ -633,7 +666,7 @@ class LamNIOpticsMixin:
|
||||
print(f" Current losaz {losaz_val:.1f}")
|
||||
print(
|
||||
" The OSA will collide with a normal sample holder at losaz "
|
||||
f"\033[1m{(collision_offset - losaz_val):.1f}\033[0m"
|
||||
f"\033[1m{(collision_offset - loptz_val):.1f}\033[0m"
|
||||
)
|
||||
print(f" Remaining space (right now): \033[1m{remaining_current:.1f}\033[0m")
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@ leyex:
|
||||
in: 13.18
|
||||
# flight tube / detector table positions used by leye_out() (*_in) and
|
||||
# leye_in() (*_out)
|
||||
fttrz_in: 1995
|
||||
fttrz_in: 1381.433
|
||||
fttrz_out: 2000
|
||||
dttrz_in: 13258
|
||||
dttrz_in: 12614.99
|
||||
dttrz_out: 13263
|
||||
deviceTags:
|
||||
- ptycho_lamni
|
||||
@@ -111,8 +111,8 @@ loptz:
|
||||
axis_Id: D
|
||||
host: mpc2680.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
- 80
|
||||
- 89
|
||||
port: 8081
|
||||
sign: -1
|
||||
enabled: true
|
||||
@@ -120,6 +120,10 @@ loptz:
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
connectionTimeout: 20
|
||||
userParameter:
|
||||
# OSA collides with the sample holder when loptz + losaz reaches this
|
||||
# value (measured 2026-10-14: loptz 77.8676, losaz 10.0029)
|
||||
collision_offset: 87.87
|
||||
deviceTags:
|
||||
- ptycho_lamni
|
||||
lsamrot:
|
||||
@@ -203,7 +207,7 @@ losax:
|
||||
readoutPriority: baseline
|
||||
connectionTimeout: 20
|
||||
userParameter:
|
||||
in: -1.582
|
||||
in: -1.66249
|
||||
deviceTags:
|
||||
- ptycho_lamni
|
||||
losay:
|
||||
@@ -223,7 +227,7 @@ losay:
|
||||
readoutPriority: baseline
|
||||
connectionTimeout: 20
|
||||
userParameter:
|
||||
in: -0.131
|
||||
in: -0.236
|
||||
out: 3.8
|
||||
deviceTags:
|
||||
- ptycho_lamni
|
||||
@@ -244,7 +248,7 @@ losaz:
|
||||
readoutPriority: baseline
|
||||
connectionTimeout: 20
|
||||
userParameter:
|
||||
in: -1
|
||||
in: 8.829
|
||||
out: -3
|
||||
deviceTags:
|
||||
- ptycho_lamni
|
||||
|
||||
Reference in new issue
Block a user