fixes for beamtime prep with Manuel #210

Merged
wakonig_k merged 5 commits from fix/beamtime_prep into main 2026-05-18 17:51:43 +02:00
6 changed files with 59 additions and 22 deletions
@@ -1055,7 +1055,7 @@ class FlomniAlignmentMixin:
with open(os.path.join(dir_path, "ptychotomoalign_Ay3.txt"), "r") as file:
tomo_alignment_fit[1][3] = file.readline()
with open(os.path.join(dir_path, "ptychotomoalign_Cy3.txt"), "r") as file:
with open(os.path.join(dir_path, "ptychotomoalign_By3.txt"), "r") as file:
tomo_alignment_fit[1][4] = file.readline()
print("New alignment parameters loaded from filesystem, meaning Matlab fit:")
@@ -1618,7 +1618,7 @@ class Flomni(
self.feye_out()
tags = ["BEC_alignment_tomo", self.sample_name]
self.write_alignment_scan_numbers(bec.queue.next_scan_number)
start_angle = 0
alignment_scan_numbers = []
@@ -1667,6 +1667,32 @@ class Flomni(
print(scilog_content)
bec.messaging.scilog.new().add_text(scilog_content.replace("\n", "<br>")).add_tags("alignmentscan").send()
def write_alignment_scan_numbers(self, first_scan):
import os
file = os.path.expanduser("~/data/raw/logs/ptychotomoalign_scannum.txt")
os.makedirs(os.path.dirname(file), exist_ok=True)
scans = [first_scan + k for k in range(5)]
angles = [0, 45, 90, 135, 180]
x_vals = []
for angle in angles:
x, y, z = self.get_alignment_offset(angle)
x_vals.append(x)
zeros = [0] * len(angles)
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(map(str, zeros)) + "\n")
def sub_tomo_scan(self, subtomo_number, start_angle=None):
"""
Performs a sub tomogram scan.
@@ -158,7 +158,7 @@ def _safe_get(device_manager, dotpath: str):
obj = device_manager.devices
for part in dotpath.split("."):
obj = getattr(obj, part)
return obj.get()
return obj.get(cached=True)
except Exception:
return None
@@ -2230,16 +2230,23 @@ function render(d){{
handleAudioForStatus(s, prevStatus);
}}
let _fetchFailCount=0;
const FETCH_FAIL_THRESHOLD=3;
async function poll(){{
try{{
const r=await fetch(STATUS_JSON, {{cache:'no-store'}});
if(!r.ok) throw new Error('HTTP '+r.status);
_fetchFailCount=0;
render(await r.json());
}}catch(e){{
console.warn('Fetch failed:',e);
document.getElementById('last-update').textContent='fetch failed - retrying...';
document.getElementById('outdated-banner').classList.add('visible');
handleStale(true);
_fetchFailCount++;
console.warn('Fetch failed:',e,'('+_fetchFailCount+')');
document.getElementById('last-update').textContent='fetch failed - retrying\u2026 ('+_fetchFailCount+')';
if(_fetchFailCount>=FETCH_FAIL_THRESHOLD){{
document.getElementById('outdated-banner').classList.add('visible');
handleStale(true);
}}
}}
}}
@@ -214,11 +214,13 @@ class JungfrauJochPreview:
r = self._socket.recv_multipart(flags=zmq.NOBLOCK)
self._parse_data(r)
except zmq.error.Again:
# No message received, this is expected when the receive queue is empty
# No new message available on Preview socket within timeout that was set
pass
except Exception as e:
# Consider moving this to debug level, but it can be useful to see why preview updates are not working
logger.info(f"Error while receiving ZMQ message from JFJ preview at {self.url}: {e}")
except Exception as exc:
logger.info(
f"Error parsing input data from JungfrauJoch host {self.url}. Exception: {exc}"
)
finally:
# Unsubscribe from the topic
self._socket.setsockopt(zmq.UNSUBSCRIBE, ZMQ_TOPIC_FILTER)
@@ -37,6 +37,7 @@ class FlomniGalilController(GalilController):
"get_motor_limit_switch",
"fosaz_light_curtain_is_triggered",
"is_motor_on",
"is_thread_active",
"all_axes_referenced",
"lights_off",
"lights_on",
+2 -1
View File
@@ -57,6 +57,7 @@ class GalilController(Controller):
"find_reference",
"get_motor_limit_switch",
"is_motor_on",
"is_thread_active",
"all_axes_referenced",
]
@@ -85,7 +86,7 @@ class GalilController(Controller):
return_val = self.socket_put_and_receive(val)
if return_val != ":":
raise GalilCommunicationError(
f"Expected return value of ':' but instead received {return_val}"
f"Sent {val} and expected return value of ':' but instead received {return_val}"
)
def is_axis_moving(self, axis_Id, axis_Id_numeric) -> bool:
+10 -10
View File
@@ -353,10 +353,13 @@ class RtFlomniController(Controller):
def laser_tracker_galil_enable(self):
ftrackz_con = self.device_manager.devices.ftrackz.obj.controller
ftrackz_con.socket_put_confirmed("tracken=1")
ftrackz_con.socket_put_confirmed("trackyct=0")
ftrackz_con.socket_put_confirmed("trackzct=0")
ftrackz_con.socket_put_confirmed("XQ#Tracker")
if not ftrackz_con.is_thread_active(5):
ftrackz_con.socket_put_confirmed("tracken=1")
ftrackz_con.socket_put_confirmed("trackyct=0")
ftrackz_con.socket_put_confirmed("trackzct=0")
ftrackz_con.socket_put_confirmed("XQ#Tracker")
while not ftrackz_con.is_thread_active(5):
time.sleep(0.1)
def laser_tracker_on_target(self) -> bool:
self.laser_update_tracker_info()
@@ -369,8 +372,8 @@ class RtFlomniController(Controller):
def laser_tracker_wait_on_target(self):
max_repeat = 25
count = 0
self.laser_tracker_galil_enable()
while not self.laser_tracker_on_target():
self.laser_tracker_galil_enable()
logger.info("Waiting for laser tracker to reach target.")
time.sleep(0.5)
count += 1
@@ -442,7 +445,7 @@ class RtFlomniController(Controller):
" interferometer error."
)
# here exception
(mode, number_of_positions_planned, current_position_in_scan) = self.get_scan_status()
mode, number_of_positions_planned, current_position_in_scan = self.get_scan_status()
if number_of_positions_planned == 0:
logger.error("Cannot start scan because no target positions are planned.")
@@ -517,14 +520,11 @@ class RtFlomniSetpointSignal(RtSetpointSignal):
tracker_status = self.parent.controller.laser_tracker_check_signalstrength()
if tracker_status == "toolow":
print(
"The interferometer signal is too low for movements. Realignment required."
)
print("The interferometer signal is too low for movements. Realignment required.")
raise RtError(
"The interferometer signal is too low for movements. Realignment required."
)
self.set_with_feedback_disabled(val)
def set_with_feedback_disabled(self, val):