Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 23 additions & 135 deletions mxcubecore/HardwareObjects/LNLS/LNLSDiffractometer.py
Original file line number Diff line number Diff line change
@@ -1,142 +1,30 @@
import time

from gevent.event import AsyncResult

from mxcubecore import HardwareRepository as HWR
from mxcubecore.HardwareObjects.GenericDiffractometer import (
GenericDiffractometer,
PhaseEnum,
from mxcubecore.HardwareObjects.abstract.AbstractDiffractometer import (
AbstractDiffractometer,
DiffractometerPhase,
)


class LNLSDiffractometer(GenericDiffractometer):
def __init__(self, name):
GenericDiffractometer.__init__(self, name)

class LNLSDiffractometer(AbstractDiffractometer):
def init(self):
GenericDiffractometer.init(self)
AbstractDiffractometer.init(self)
self._bluesky_api = HWR.beamline.get_object_by_role("bluesky")
self.pixels_per_mm_x = 10**-4
self.pixels_per_mm_y = 10**-4
self.beam_position = [318, 238]
self.in_plate_mode = False
self.last_centred_position = self.beam_position
self.current_motor_positions = {
"phiy": 0,
"sampx": 0,
"sampy": 0,
"zoom": 0,
"focus": 0,
"phiz": 0,
"phi": 0,
"kappa": 0,
"kappa_phi": 0,
}

self.centring_time = 0
self.mount_mode = self.get_property("sample_mount_mode")
if self.mount_mode is None:
self.mount_mode = "manual"

self.connect(self.motor_hwobj_dict["phi"], "valueChanged", self.phi_motor_moved)
self.connect(
self.motor_hwobj_dict["phiy"], "valueChanged", self.phiy_motor_moved
)
self.connect(
self.motor_hwobj_dict["phiz"], "valueChanged", self.phiz_motor_moved
)
self.connect(
self.motor_hwobj_dict["kappa"], "valueChanged", self.kappa_motor_moved
)
self.connect(
self.motor_hwobj_dict["kappa_phi"],
"valueChanged",
self.kappa_phi_motor_moved,
)
self.connect(
self.motor_hwobj_dict["sampx"], "valueChanged", self.sampx_motor_moved
)
self.connect(
self.motor_hwobj_dict["sampy"], "valueChanged", self.sampy_motor_moved
)

def is_ready(self) -> bool:
self.current_phase = DiffractometerPhase.UNKNOWN
self.update_state(self.STATES.READY)
self.connect(self.sampx, "valueChanged", self.sampx.update_grid_value)
self.connect(self.sampy, "valueChanged", self.sampy.update_grid_value)

def get_pixels_per_mm(self):
zoom_enum = self.zoom.get_value()
current_zoom = zoom_enum.name
mm_per_pixel_x = self.zoom.get_property("mm_per_pixel_x")[current_zoom]
mm_per_pixel_y = self.zoom.get_property("mm_per_pixel_y")[current_zoom]
pixel_per_mm_x = round(1 / mm_per_pixel_x, 6)
pixel_per_mm_y = round(1 / mm_per_pixel_y, 6)
return (pixel_per_mm_x, pixel_per_mm_y)

def save_centring_positions(self):
self.update_state(self.STATES.READY)

def wait_status_ready(self, timeout=None):
return True

def phi_motor_moved(self, pos):
self.current_motor_positions["phi"] = pos
self.emit("phiMotorMoved", pos)

def phiy_motor_moved(self, pos):
self.current_motor_positions["phiy"] = pos

def phiz_motor_moved(self, pos):
self.current_motor_positions["phiz"] = pos

def sampx_motor_moved(self, pos):
self.current_motor_positions["sampx"] = pos

def sampy_motor_moved(self, pos):
self.current_motor_positions["sampy"] = pos

def kappa_motor_moved(self, pos):
self.current_motor_positions["kappa"] = pos
if time.time() - self.centring_time > 1.0:
self.invalidate_centring()
self.emit_diffractometer_moved()
self.emit("kappaMotorMoved", pos)

def kappa_phi_motor_moved(self, pos):
self.current_motor_positions["kappa_phi"] = pos
if time.time() - self.centring_time > 1.0:
self.invalidate_centring()
self.emit_diffractometer_moved()
self.emit("kappaPhiMotorMoved", pos)

def manual_centring(self):
self.log.info("Initializing manual sample alignment...")
for step in range(3):
self.log.info(f"Step {step + 1} of 3...")
self.user_clicked_event = AsyncResult()
self.waiting_for_click = True
x, y = self.user_clicked_event.get()
self.log.info(f"{x}, {y}")
self._bluesky_api.execute_plan(
plan_name="manual_alignment",
kwargs={"x_px": x, "y_px": y, "step": step},
)
self.log.info("Manual sample alignment has finished...")
return {}

def automatic_centring(self):
self.log.info("Initializing automatic sample alignment...")
self._bluesky_api.execute_plan(plan_name="automatic_alignment")
self.log.info("Automatic sample alignment has finished...")

def move_to_beam(self, x, y, omega=None):
self.log.info("Moving to beam...")

self._bluesky_api.execute_plan(
plan_name="move_to_beam",
kwargs={
"x_px": x - self.beam_position[0],
"y_px": y - self.beam_position[1],
},
)
self.log.info("Move to beam has finished...")

def motor_positions_to_screen(self, motor_positions):
return self.beam_position

def get_value_motors(self):
return self.current_motor_positions

def get_phase(self):
unknown_phase = PhaseEnum.unknown
phase = self.get_current_phase()
if not phase:
phase = unknown_phase
return phase

def get_chip_configuration(self):
return None
172 changes: 172 additions & 0 deletions mxcubecore/HardwareObjects/LNLS/LNLSSampleView.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import logging

import gevent
from mxcubeweb.app import MXCUBEApplication as frontendApplication
from mxcubeweb.core.util.convertutils import to_camel

from mxcubecore import HardwareRepository as HWR
from mxcubecore.HardwareObjects.abstract.AbstractSampleChanger import SampleChangerState
from mxcubecore.HardwareObjects.SampleView import Grid, SampleView


class LNLSSampleView(SampleView):
def init(self):
SampleView.init(self)
self.user_level_log = logging.getLogger("user_level_log")
self._bluesky_api = HWR.beamline.get_object_by_role("bluesky")
self.sc = HWR.beamline.get_object_by_role("sample_changer")
self.READY_FOR_NEXT_CLICK = gevent.event.Event()
self.x, self.y = None, None
self.frontend_application = frontendApplication
self.current_centring_method = None

def move_to_beam_bluesky(self, x, y, plan_name, step=-1):
beam_pos = HWR.beamline.beam.get_beam_position_on_screen()
plan_kwargs = {
"x_px": beam_pos[0] - x,
"y_px": y - beam_pos[1],
}
if step != -1:
plan_kwargs["step"] = step
self._bluesky_api.execute_plan(plan_name=plan_name, kwargs=plan_kwargs)

def move_to_beam(self, x, y):
if self.sc.get_state() != SampleChangerState.Ready:
return
self.user_level_log.info("Moving to beam...")
self.move_to_beam_bluesky(x, y, "move_to_beam")
self.user_level_log.info("Move to beam has finished...")

def start_centring(self, centring_method):
self.current_centring_method = centring_method
self.current_centring_procedure = centring_method
self.emit("centringStarted", (centring_method))

def finish_centring(self):
self.centring_status["valid"] = True
omega, phiy, phiz, sampx, sampy = self.get_current_diffractometer_positions()
self.centring_status["motors"] = {
"omega": omega,
"phiy": phiy,
"phiz": phiz,
"sampx": sampx,
"sampy": sampy,
}
self.emit(
"centringSuccessful",
(self.current_centring_method, self.get_centring_status()),
)
if self.current_centring_method == "Manual":
self.shapes.clear()
self.frontend_application.server.emit(
"update_shapes", {"shapes": self.shapes}, namespace="/hwr"
)
self.frontend_application.server.emit("abort_centring", namespace="/hwr")
self.current_centring_procedure = None
self.current_centring_method = None

def start_auto_centring(self):
self.user_level_log.info("Initializing automatic sample alignment...")
if self.current_centring_method is not None:
self.user_level_log.info("Already centring")
return
self.start_centring("Automatic")
self._bluesky_api.execute_plan(plan_name="automatic_alignment")
self.user_level_log.info("Automatic sample alignment has finished...")
self.finish_centring()

def image_clicked(self, x, y):
logging.getLogger("user_level_log").info(
f"LNLS Centring click at x:{int(x)}, y:{int(y)}"
)
self.x = x
self.y = y
self.READY_FOR_NEXT_CLICK.set()

def start_manual_centring(self, nb_click: int = 3):
if self.sc.get_state() != SampleChangerState.Ready:
return
self.user_level_log.info("Initializing manual sample alignment...")
if self.current_centring_method is not None:
self.user_level_log.info("Already centring")
return
self.start_centring("Manual")
for step in range(3):
self.READY_FOR_NEXT_CLICK.clear()
self.READY_FOR_NEXT_CLICK.wait()
if (self.x is not None) and (self.y is not None):
self.move_to_beam_bluesky(self.x, self.y, "manual_alignment", step)
self.x = None
self.y = None
self.user_level_log.info("Manual sample alignment has finished...")
self.finish_centring()

def get_snapshot(self):
return None

def _wait_for_centring_finishes(self):
return

def get_current_diffractometer_positions(self):
d = HWR.beamline.diffractometer
omega = d.omega.get_value()
phiy = d.phiy.get_value()
phiz = d.phiz.get_value()
sampx = d.sampx.get_value()
sampy = d.sampy.get_value()
return omega, phiy, phiz, sampx, sampy

def get_current_mm_per_pixel(self):
d = HWR.beamline.diffractometer
zoom_enum = d.zoom.get_value()
current_zoom = zoom_enum.name
mm_per_pixel_x = d.zoom.get_property("mm_per_pixel_x")[current_zoom]
mm_per_pixel_y = d.zoom.get_property("mm_per_pixel_y")[current_zoom]
return mm_per_pixel_x, mm_per_pixel_y

def get_centred_point_from_coord(self, x, y, return_by_names=None):
omega, phiy, phiz, sampx, sampy = self.get_current_diffractometer_positions()

beam_pos = HWR.beamline.beam.get_beam_position_on_screen()
x_px = beam_pos[0] - x
y_px = y - beam_pos[1]

mm_per_pixel_x, mm_per_pixel_y = self.get_current_mm_per_pixel()

sampx = sampx + x_px * mm_per_pixel_x
sampy = sampy + y_px * mm_per_pixel_y

return {
"omega": omega,
"phiy": phiy,
"phiz": phiz,
"sampx": sampx,
"sampy": sampy,
}

def _update_shape_positions(self, *args, **kwargs):
for shape in self.get_shapes():
if not isinstance(shape, Grid):
shape.update_position(self.motor_positions_to_screen)
self.emit("shapesChanged")

def update_grid_positions(self, pixel_diff_x, pixel_diff_y):
final_shape_dict = {}
grid_list = self.get_grids()
for grid in grid_list:
shape = self.get_shape(grid.id)
shape_dict = to_camel(shape.as_dict())
previous_coord = shape_dict["screenCoord"]
new_coord = [
(previous_coord[0] - pixel_diff_x),
previous_coord[1] - pixel_diff_y,
]
shape_dict["screenCoord"] = new_coord
shape_dict["cellCountFun"] = "left-to-right"
grid.update_from_dict({"screenCoord": new_coord})
grid.screen_coord = new_coord
final_shape_dict.update({grid.id: shape_dict})
self.frontend_application.server.emit(
"update_shapes", {"shapes": final_shape_dict}, namespace="/hwr"
)
self.emit("shapesChanged")
Loading