Merge branch 'main' into feat/slit_gui
This commit is contained in:
@@ -2560,6 +2560,10 @@ class Flomni(
|
||||
+ self.manual_shift_y
|
||||
)
|
||||
sum_offset_z = offsets[2]
|
||||
|
||||
# TODO this fix is while the tracker z is broken
|
||||
probe_propagation = -sum_offset_z * 1e-6
|
||||
sum_offset_z = 0
|
||||
|
||||
# --- positioning + laser tracker, mirroring
|
||||
# flomni_fermat_scan._prepare_setup_part2 ---
|
||||
@@ -2580,6 +2584,7 @@ class Flomni(
|
||||
# --- acquire ---
|
||||
n_frames = frames_per_trigger if frames_per_trigger is not None else self.frames_per_trigger
|
||||
scans.acquire(exp_time=self.tomo_countingtime, frames_per_trigger=n_frames)
|
||||
self.tomo_reconstruct(probe_propagation=probe_propagation)
|
||||
|
||||
def _tomo_type1_actual_grid(self) -> tuple[int, float, int]:
|
||||
"""Compute the actual (achievable) tomo_type==1 grid from the
|
||||
@@ -2618,13 +2623,17 @@ class Flomni(
|
||||
print(f"Frames per trigger (burst) = {self.frames_per_trigger}")
|
||||
print(f"Single point instead of fermat = {self.single_point_instead_of_fermat_scan}")
|
||||
print("")
|
||||
|
||||
if self.tomo_type == 1:
|
||||
print("\x1b[1mTomo type 1:\x1b[0m 8 equally spaced sub-tomograms")
|
||||
print(f"Angular range = {self.tomo_angle_range} degrees")
|
||||
print(
|
||||
f"Total number of projections: {(self.tomo_angle_range/self.tomo_angle_stepsize)*8}"
|
||||
)
|
||||
print(f"Angular step within sub-tomogram: {self.tomo_angle_stepsize} degrees")
|
||||
# N, step, total_projections all come from the same helper
|
||||
# sub_tomo_scan() effectively uses internally - see
|
||||
# _tomo_type1_actual_grid() for why this can't just read
|
||||
# self.tomo_angle_stepsize directly.
|
||||
_, achievable_step, total_projections = self._tomo_type1_actual_grid()
|
||||
print(f"Total number of projections: {total_projections}")
|
||||
print(f"Angular step within sub-tomogram: {achievable_step:.3f} degrees")
|
||||
print(
|
||||
"Angular step of the final (combined) tomogram:"
|
||||
f" {self.tomo_angle_range / total_projections:.3f} degrees"
|
||||
|
||||
@@ -98,8 +98,9 @@ class FlomniOpticsMixin:
|
||||
dev.rtx.controller.feedback_disable()
|
||||
|
||||
self.fosa_out()
|
||||
foptx_out = self._get_user_param_safe("foptx", "out")
|
||||
fopty_out = self._get_user_param_safe("fopty", "out")
|
||||
umv(dev.fopty, fopty_out)
|
||||
umv(dev.foptx, foptx_out, dev.fopty, fopty_out)
|
||||
|
||||
if "rtx" in dev and dev.rtx.enabled:
|
||||
time.sleep(1)
|
||||
@@ -237,7 +238,7 @@ class FlomniOpticsMixin:
|
||||
|
||||
console.print(table)
|
||||
|
||||
diameters = [150e-6, 250e-6]
|
||||
diameters = [140e-6, 170e-6, 200e-6, 250e-6]
|
||||
|
||||
console = Console()
|
||||
table = Table(title="Outermost zone width \033[1m30 nm\033[0m", box=box.SQUARE)
|
||||
|
||||
@@ -70,14 +70,26 @@ class XrayEyeAlign:
|
||||
# so a second submission at step==1 is treated as the real angle-0
|
||||
# fit point instead of triggering another height correction.
|
||||
self._height_centered = False
|
||||
# Raw pixel coords + ROI size collected at each submit:
|
||||
# [[step_k, x_px, y_px, w_px, h_px, image_idx], ...]
|
||||
# image_idx refers to alignment_images[image_idx], i.e. the last
|
||||
# frame captured before that submit (shutter is closed at submit time).
|
||||
self.roi_pixel_data = []
|
||||
|
||||
def _save_alignment_data(self, file_path: str):
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
with h5py.File(os.path.expanduser(file_path), "w") as f:
|
||||
def _save_alignment_data(self, file_path: str, fit_data: np.ndarray | None = None):
|
||||
expanded = os.path.expanduser(file_path)
|
||||
os.makedirs(os.path.dirname(expanded), exist_ok=True)
|
||||
with h5py.File(expanded, "w") as f:
|
||||
f.create_dataset(
|
||||
"alignment_values", data=np.array(list(self.alignment_values.values()))
|
||||
)
|
||||
f.create_dataset("alignment_images", data=np.array(self.alignment_images))
|
||||
if self.roi_pixel_data:
|
||||
ds = f.create_dataset("roi_pixel_data", data=np.array(self.roi_pixel_data))
|
||||
ds.attrs["columns"] = ["step_k", "x_px", "y_px", "w_px", "h_px", "image_idx"]
|
||||
if fit_data is not None:
|
||||
ds = f.create_dataset("alignment_fit", data=fit_data)
|
||||
ds.attrs["rows"] = ["angles_deg", "offsets_um", "zeros"]
|
||||
|
||||
def update_frame(self, keep_shutter_open=False):
|
||||
if self.flomni._flomnigui_check_attribute_not_exists("xeyegui"):
|
||||
@@ -220,6 +232,20 @@ class XrayEyeAlign:
|
||||
# reset submit channel
|
||||
dev.omny_xray_gui.submit.set(0)
|
||||
|
||||
# Raw pixel position and ROI size at submit time.
|
||||
# The relevant image is the last captured frame (shutter is
|
||||
# closed by the time the user clicks submit).
|
||||
_raw_x = getattr(dev.omny_xray_gui, f"xval_x_{k}").get()
|
||||
_raw_y = getattr(dev.omny_xray_gui, f"yval_y_{k}").get()
|
||||
_raw_w = getattr(dev.omny_xray_gui, f"width_x_{k}").get()
|
||||
_raw_h = getattr(dev.omny_xray_gui, f"width_y_{k}").get()
|
||||
_img_idx = len(self.alignment_images) - 1
|
||||
print(
|
||||
f" Submit k={k}: px x={_raw_x:.1f} y={_raw_y:.1f} "
|
||||
f"w={_raw_w:.1f} h={_raw_h:.1f} img={_img_idx}"
|
||||
)
|
||||
self.roi_pixel_data.append([k, _raw_x, _raw_y, _raw_w, _raw_h, _img_idx])
|
||||
|
||||
# Controls whether `k` advances to the next step below. Left
|
||||
# True except for the height-centering submission, which
|
||||
# reuses k==1 for a second, real submission afterwards.
|
||||
@@ -252,9 +278,13 @@ class XrayEyeAlign:
|
||||
self.gui.show_crosshair()
|
||||
|
||||
self.send_message(
|
||||
"Adjust sample height with the arrows if needed, then mark "
|
||||
"the sample and submit - height will be centered automatically"
|
||||
)
|
||||
<<<<<<< Updated upstream
|
||||
"Submit height. Use arrows if far off."
|
||||
=======
|
||||
"Adjust sample height with the arrows if needed, then mark "
|
||||
"the sample and submit - height will be centered automatically"
|
||||
>>>>>>> Stashed changes
|
||||
)
|
||||
self.gui.enable_submit_button(True)
|
||||
self.movement_buttons_enabled(True, True)
|
||||
|
||||
@@ -373,37 +403,22 @@ class XrayEyeAlign:
|
||||
)
|
||||
|
||||
def write_output(self):
|
||||
file = os.path.expanduser("~/data/raw/logs/xrayeye_alignmentvalues/xrayeye_alignmentvalues")
|
||||
timestamp = time.strftime("%Y%m%d_%H%M%S")
|
||||
self._save_alignment_data(file + f"_image_data_{timestamp}.h5")
|
||||
if not os.path.exists(file):
|
||||
os.makedirs(os.path.dirname(file), exist_ok=True)
|
||||
file_h5 = f"~/data/raw/logs/xrayeye_alignmentvalues/xrayeye_alignmentvalues_{timestamp}.h5"
|
||||
|
||||
with open(file, "w") as alignment_values_file:
|
||||
alignment_values_file.write("angle\thorizontal\n")
|
||||
fovx_offsets = np.zeros(5)
|
||||
for k in range(1, 6):
|
||||
fovx_offset = self.alignment_values[0] - self.alignment_values[k]
|
||||
fovx_offsets[k - 1] = fovx_offset
|
||||
print(f"Alignment number {k}, value x {fovx_offset}")
|
||||
|
||||
# Initialize an empty list to store fovx values
|
||||
fovx_list = []
|
||||
fovx_offsets = np.zeros(5) # holds offsets for k = 1..5
|
||||
|
||||
for k in range(1, 6):
|
||||
fovx_offset = self.alignment_values[0] - self.alignment_values[k]
|
||||
fovx_offsets[k - 1] = fovx_offset # store in array
|
||||
|
||||
fovx_x = (k - 1) * 45
|
||||
fovx_list.append([fovx_x, fovx_offset * 1000]) # Append the data to the list
|
||||
|
||||
print(f"Alignment number {k}, value x {fovx_offset}")
|
||||
alignment_values_file.write(f"{fovx_x}\t{fovx_offset * 1000}\n")
|
||||
|
||||
# Now build final numpy array:
|
||||
data = np.array(
|
||||
[
|
||||
[0, 45, 90, 135, 180], # angles
|
||||
fovx_offsets * 1000, # fovx_offset values
|
||||
[0, 0, 0, 0, 0],
|
||||
]
|
||||
)
|
||||
data = np.array(
|
||||
[
|
||||
[0, 45, 90, 135, 180], # angles
|
||||
fovx_offsets * 1000, # fovx_offset values
|
||||
[0, 0, 0, 0, 0],
|
||||
]
|
||||
)
|
||||
self._save_alignment_data(file_h5, fit_data=data)
|
||||
self.gui.submit_fit_array(data)
|
||||
print(f"fit submited with {data}")
|
||||
# self.flomni.flomnigui_show_xeyealign_fittab()
|
||||
print(f"fit submited with {data}")
|
||||
@@ -76,7 +76,10 @@ foptx:
|
||||
connectionTimeout: 20
|
||||
userParameter:
|
||||
#170 micron, 60 nm
|
||||
in: -13.831
|
||||
#in: -13.831
|
||||
#250 micron, 30 nm, Abe structures
|
||||
in: -13.8809375
|
||||
out: -14.1809
|
||||
fopty:
|
||||
description: Optics Y
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fgalil_ophyd.FlomniGalilMotor
|
||||
@@ -95,8 +98,11 @@ fopty:
|
||||
connectionTimeout: 20
|
||||
userParameter:
|
||||
#170 micron, 60 nm
|
||||
in: 0.42
|
||||
out: 0.57
|
||||
#in: 0.42
|
||||
#out: 0.57
|
||||
#250 micron, 30 nm, Abe structures
|
||||
in: 2.8299
|
||||
out: 2.8299
|
||||
foptz:
|
||||
description: Optics Z
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fgalil_ophyd.FlomniGalilMotor
|
||||
@@ -157,7 +163,7 @@ fsamy:
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- 2
|
||||
- 3.3
|
||||
- 3.8
|
||||
port: 8081
|
||||
sign: 1
|
||||
enabled: true
|
||||
@@ -305,7 +311,10 @@ fosax:
|
||||
#in: 8.7568
|
||||
#out: 5.1
|
||||
#170 micron, 60 nm, 7.9 kev
|
||||
in: 8.731922
|
||||
# in: 8.731922
|
||||
# out: 5.1
|
||||
#250 micron, 30 nm, Abe structures
|
||||
in: 8.755141
|
||||
out: 5.1
|
||||
fosay:
|
||||
description: OSA Y
|
||||
@@ -327,8 +336,9 @@ fosay:
|
||||
#170 micron, 60 nm, 7.6 kev
|
||||
#in: -0.0235
|
||||
#170 micron, 60 nm, 7.6 kev
|
||||
in: -0.0422
|
||||
|
||||
#in: -0.0422
|
||||
#250 micron, 30 nm, Abe structures
|
||||
in: -2.357436
|
||||
fosaz:
|
||||
description: OSA Z
|
||||
deviceClass: csaxs_bec.devices.smaract.smaract_ophyd.SmaractMotor
|
||||
@@ -350,8 +360,11 @@ fosaz:
|
||||
#in: 8.5
|
||||
#out: 6
|
||||
#170 micron, 60 nm, 7.9 kev, foptz 15.9
|
||||
in: 11.9
|
||||
out: 6
|
||||
# in: 11.9
|
||||
# out: 6
|
||||
# micron, 30 nm, 7.9 kev, foptz 32 //abe's fzp's
|
||||
in: -2
|
||||
out: -5
|
||||
|
||||
############################################################
|
||||
#################### flOMNI RT motors ######################
|
||||
|
||||
@@ -48,13 +48,12 @@ Manually move the gripper to a transfer position
|
||||
#### Coarse alignment
|
||||
|
||||
After the sample transfer the sample stage moved to the measurement position with your new sample. The Xray eye will automatically move in and the shutter will open. You may already see the sample in the omny xeye interface running on the windows computer.
|
||||
+Height is now centered automatically as part of step 3 below, so manual height adjustment is only needed if the sample is far off screen to begin with:
|
||||
If you see your sample already at the approximately correct height, you can skip steps 1 to 3. Otherwise adjust the height:
|
||||
|
||||
|
||||
+1. If the sample is far off screen, `flomni.feedback_disable()` then `flomni.umvr_fsamy_tracked(0.01)`, attention: unit <mm>, move the sample stage relative up (positive) or down (negative) until the sample is visible in the xray eye screen, then `flomni.feedback_enable_with_reset()`
|
||||
1. `flomni.feedback_disable()` disable the closed loop operation to allow movement of coarse stages
|
||||
1. `umvr(dev.fsamy, 0.01)`, attention: unit <mm>, move the sample stage relative up (positive) or down (negative) until the sample is approximately vertically centered in xray eye screen
|
||||
1. `flomni.xrayeye_update_frame()` will update the current image on the xray eye screen
|
||||
+1. `flomni.xrayeye_alignment_start()` start the coarse alignment: mark the sample once to auto-center its height, then measure (clicking in the X-ray eye software) the sample position at 0, 45, 90, 135, 180 degrees. The GUI will present a fit of this data, which is automatically loaded to BEC for aligning the sample.
|
||||
|
||||
1. `flomni.xrayeye_alignment_start()` start the coarse alignment of the sample by measuring (clicking in the X-ray eye software) the sample position at its height and angles of 0, 45, 90, 135, 180 degrees. The GUI will present a fit of this data, which is automatically loaded to BEC for aligning the sample.
|
||||
|
||||
#### Fine alignment
|
||||
|
||||
@@ -363,5 +362,4 @@ flomni.move_fheater_up()
|
||||
|
||||
The functions are safe in the sense that no collisions should occur. E.g. the OSA will be moved back before a movement of the heater.
|
||||
|
||||
__The heater still needs commissioning in BEC!!!__
|
||||
|
||||
__The heater still needs commissioning in BEC!!!__
|
||||
@@ -271,8 +271,8 @@ def device_manager_mock():
|
||||
},
|
||||
"num_points": 2,
|
||||
"positions": [
|
||||
[1.3681828686580249, 2.1508313829565293],
|
||||
[-0.7700589354581364, -0.8406005210092851],
|
||||
[1.3681828686580249, 2.1508313829565293],
|
||||
],
|
||||
"scan_name": "lamni_fermat_scan",
|
||||
"scan_type": "step",
|
||||
|
||||
Reference in New Issue
Block a user