diff --git a/mxcubecore/HardwareObjects/DESY/Centring.py b/mxcubecore/HardwareObjects/DESY/Centring.py
index f195cc1e57..84f4f58bdd 100644
--- a/mxcubecore/HardwareObjects/DESY/Centring.py
+++ b/mxcubecore/HardwareObjects/DESY/Centring.py
@@ -18,7 +18,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with MXCuBE. If not, see .
-__copyright__ = """ Copyright © 2010 - 2020 by MXCuBE Collaboration """
+__copyright__ = """ Copyright © 2010 - 2024 by MXCuBE Collaboration """
__license__ = "LGPLv3+"
diff --git a/mxcubecore/HardwareObjects/DESY/MjpgStreamVideo.py b/mxcubecore/HardwareObjects/DESY/MjpgStreamVideo.py
index 310bb967a6..4fe19d06f8 100644
--- a/mxcubecore/HardwareObjects/DESY/MjpgStreamVideo.py
+++ b/mxcubecore/HardwareObjects/DESY/MjpgStreamVideo.py
@@ -968,7 +968,7 @@ def _do_imagePolling(self, sleep_time):
# image.setOffset(QPoint(300,300))
# self.image = QPixmap.fromImage(image)
self.image = QPixmap.fromImage(
- image.scaled(self.display_width, self.display_height)
+ image.scaled(int(self.display_width), int(self.display_height))
)
self.emit("imageReceived", self.image)
# gevent.sleep(0.1)
diff --git a/mxcubecore/HardwareObjects/DESY/P11AlbulaView.py b/mxcubecore/HardwareObjects/DESY/P11AlbulaView.py
index 4062d1db26..8d51ebb028 100644
--- a/mxcubecore/HardwareObjects/DESY/P11AlbulaView.py
+++ b/mxcubecore/HardwareObjects/DESY/P11AlbulaView.py
@@ -18,7 +18,9 @@
# You should have received a copy of the GNU Lesser General Public License
# along with MXCuBE. If not, see .
-__copyright__ = """ Copyright © 2010 - 2023 by MXCuBE Collaboration """
+from mxcubecore.BaseHardwareObjects import HardwareObject
+
+__copyright__ = """ Copyright © 2010 - 2024 by MXCuBE Collaboration """
__license__ = "LGPLv3+"
@@ -26,10 +28,8 @@
import time
from PIL import Image
-
sys.path.append("/opt/dectris/albula/4.0/python/")
-from mxcubecore.BaseHardwareObjects import HardwareObject
try:
from dectris import albula
@@ -99,7 +99,7 @@ def start(self, path=None, filetype=None, interval=None, stream=False):
self.eigerThread.clearMonitorBuffer()
self.eigerThread.setMonitorDiscardNew(True)
- super(LiveView, self).start()
+ super().start()
def stop(self, interval=0.0):
diff --git a/mxcubecore/HardwareObjects/DESY/P11BackLight.py b/mxcubecore/HardwareObjects/DESY/P11BackLight.py
index 8371619b50..2dc8117446 100644
--- a/mxcubecore/HardwareObjects/DESY/P11BackLight.py
+++ b/mxcubecore/HardwareObjects/DESY/P11BackLight.py
@@ -53,7 +53,7 @@ class P11BackLight(AbstractNState):
def __init__(self, name):
- super(AbstractNState, self).__init__(name)
+ super().__init__(name)
self.cmd_open_close = None
self.cmd_started = 0
@@ -72,7 +72,7 @@ def init(self):
self.chan_value.connect_signal("update", self.update_light_state)
self.update_light_state(self.chan_value.get_value())
- super(AbstractNState, self).init()
+ super().init()
def get_value(self):
return self.update_light_state()
diff --git a/mxcubecore/HardwareObjects/DESY/P11Beam.py b/mxcubecore/HardwareObjects/DESY/P11Beam.py
new file mode 100644
index 0000000000..318911d1fa
--- /dev/null
+++ b/mxcubecore/HardwareObjects/DESY/P11Beam.py
@@ -0,0 +1,107 @@
+# Project: MXCuBE
+# https://github.com/mxcube
+#
+# This file is part of MXCuBE software.
+#
+# MXCuBE is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# MXCuBE is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with MXCuBE. If not, see .
+
+"""P11Beam"""
+
+from mxcubecore.HardwareObjects.abstract.AbstractBeam import AbstractBeam
+from mxcubecore.BaseHardwareObjects import HardwareObjectState
+
+
+__credits__ = ["DESY P11"]
+__license__ = "LGPLv3+"
+__category__ = "General"
+
+
+class P11Beam(AbstractBeam):
+ def __init__(self, *args):
+ super().__init__(*args)
+
+ self._beam_size_dict = {"aperture": [9999, 9999], "slits": [9999, 9999]}
+
+ self._beam_position_on_screen = [340, 256]
+
+ self.focus_sizes = {
+ -1: {"label": "unknown", "size": (0.2, 0.2)},
+ 0: {"label": "flat", "size": (0.2, 0.2)},
+ 1: {"label": "200x200", "size": (0.2, 0.2)},
+ 2: {"label": "100x100", "size": (0.1, 0.1)},
+ 3: {"label": "50x50", "size": (0.05, 0.05)},
+ 4: {"label": "20x20", "size": (0.02, 0.02)},
+ 5: {"label": "4x9", "size": (0.009, 0.004)},
+ }
+
+ def init(self):
+ self.mirror_idx_ch = self.get_channel_object("beamsize")
+ self.mirror_state_ch = self.get_channel_object("state")
+
+ if self.mirror_idx_ch is not None:
+ self.mirror_idx_ch.connect_signal("update", self.mirror_idx_changed)
+ if self.mirror_state_ch is not None:
+ self.mirror_state_ch.connect_signal("update", self.mirror_state_changed)
+
+ self.mirror_idx_changed()
+ self.mirror_state_changed()
+
+ def get_beam_info_state(self):
+ if self.mirror_state_ch is not None:
+ tango_state = self.mirror_state_ch.get_value()
+ return self._convert_tango_state(tango_state)
+
+ return self.STATES_READY
+
+ def get_slits_gap(self):
+ return None, None
+
+ def mirror_state_changed(self, state=None):
+
+ if state is None:
+ state = self.get_beam_info_state()
+
+ self.update_state(self._convert_tango_state(state))
+
+ def _convert_tango_state(self, state):
+ str_state = str(state)
+
+ if str_state == "ON":
+ _state = self.STATES.READY
+ elif str_state == "MOVING":
+ _state = self.STATES.BUSY
+ else:
+ _state = self.STATES.FAULT
+ return _state
+
+ def mirror_idx_changed(self, value=None):
+
+ if value is None:
+ value = self.mirror_idx_ch.get_value()
+
+ self.log.debug(f"P11Beam - mirror idx changed. now is {value}")
+
+ if value not in self.focus_sizes:
+ value = -1
+ self.log.debug(f" - UNKNOWN mirror index")
+
+ curr_size_item = self.focus_sizes[value]
+ self.log.debug(
+ f" current mirror focus is {curr_size_item['label']}: {curr_size_item['size']}"
+ )
+
+ self._beam_size_dict["aperture"] = curr_size_item["size"]
+
+ self.evaluate_beam_info()
+ self.re_emit_values()
diff --git a/mxcubecore/HardwareObjects/DESY/P11Collect.py b/mxcubecore/HardwareObjects/DESY/P11Collect.py
index 3171a52753..9cac094595 100644
--- a/mxcubecore/HardwareObjects/DESY/P11Collect.py
+++ b/mxcubecore/HardwareObjects/DESY/P11Collect.py
@@ -18,7 +18,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with MXCuBE. If not, see .
-__copyright__ = """ Copyright © 2010 - 2023 by MXCuBE Collaboration """
+__copyright__ = """ Copyright © 2010 - 2024 by MXCuBE Collaboration """
__license__ = "LGPLv3+"
@@ -39,24 +39,39 @@
from mxcubecore.Command.Tango import DeviceProxy
+import gevent
+import time
+import numpy as np
+import logging
+import os
+import sys
+import h5py
import triggerUtils
+from tango import DeviceProxy, DevState
FILE_TIMEOUT = 5
class P11Collect(AbstractCollect):
def __init__(self, *args):
- super(P11Collect, self).__init__(*args)
+ super().__init__(*args)
+
+ def init(self):
+
+ super().init()
+
+ # os.system("/opt/xray/bin/adxv -socket -colors Gray -rings &")
+
+ # os.system("/bin/bash /gpfs/local/shared/MXCuBE/STRELA/start_viewer_zmq.sh")
self.default_speed = self.get_property("omega_default_speed", 130)
- self.turnback_time = self.get_property("turnback_time", 0.1)
+ self.turnback_time = self.get_property("turnback_time", 0.3)
self.filter_server_name = self.get_property("filterserver")
self.mono_server_name = self.get_property("monoserver")
self.filter_server = DeviceProxy(self.filter_server_name)
self.mono_server = DeviceProxy(self.mono_server_name)
- self.diffr = HWR.beamline.diffractometer
self.lower_bound_ch = self.get_channel_object("acq_lower_bound")
self.upper_bound_ch = self.get_channel_object("acq_upper_bound")
@@ -66,18 +81,6 @@ def __init__(self, *args):
self.acq_off_cmd = self.get_command_object("acq_off")
self.acq_window_off_cmd = self.get_command_object("acq_window_off")
- self.latest_frames = 1
- self.acq_speed = 1.0
- self.init_ok = False
- self.latest_h5_filename = "TEST_master.h5"
-
- def init(self):
- super(P11Collect, self).init()
-
- # os.system("/opt/xray/bin/adxv -socket -colors Gray -rings &")
-
- # os.system("/bin/bash /gpfs/local/shared/MXCuBE/STRELA/start_viewer_zmq.sh")
-
if None in [
self.lower_bound_ch,
self.upper_bound_ch,
@@ -124,6 +127,9 @@ def data_collection_hook(self):
"P11Collect. - object initialization failed. COLLECTION not possible"
)
+ osc_pars["kappa"] = 0
+ osc_pars["kappa_phi"] = 0
+
self.diffr = HWR.beamline.diffractometer
detector = HWR.beamline.detector
@@ -167,13 +173,6 @@ def data_collection_hook(self):
if not ret:
raise BaseException("Cannot set prepare collection . Aborting")
- # writeInfo (is it necessary?)
-
- # # Separate_instance of the modified Dectris pyqt Viewer.
- # print("=============== STARTING THE VIEWER ===============")
- # new_gui = subprocess.Popen("/bin/bash /gpfs/local/shared/MXCuBE/STRELA/start_viewer.sh")
- # print("=============== FINISHED STARTING THE VIEWER ===============")
-
try:
self.log.debug("############# #COLLECT# Opening detector cover")
self.diffr.detector_cover_open(wait=True)
@@ -201,6 +200,11 @@ def data_collection_hook(self):
# Filepath to the EDNA processing
# filepath = os.path.join(basepath,"%s_%d" % (prefix, runno))
+ # setting up xds_dir for characterisation (used there internally to create dirs)
+ self.current_dc_parameters["xds_dir"] = os.path.join(
+ basepath, "%s_%d" % (prefix, runno)
+ )
+
self.log.debug(
"======= CURRENT FILEPATH: "
+ str(filepath)
@@ -213,16 +217,6 @@ def data_collection_hook(self):
+ "======================================="
)
- # # === if folder exists - increase run number
- # print("========CHECKING EXISTING DIRECTORY ===========")
- # print(os.path.exists(self.latest_h5_filename))
- # if os.path.exists(self.latest_h5_filename):
- # print("======= File exists! Increasing run number ===========")
- # self.current_dc_parameters["fileinfo"]["run_number"]=self.current_dc_parameters["fileinfo"]["run_number"]+1
- # print("Run number has changed to ", self.current_dc_parameters["fileinfo"]["run_number"])
- # runno = self.current_dc_parameters["fileinfo"]["run_number"]
- # filepath = os.path.join(basepath,prefix,"screening_"+str(runno).zfill(3)+"/"+"%s_%d" % (prefix, runno))
-
self.log.debug(
"======= CURRENT FILEPATH: "
+ str(filepath)
@@ -235,7 +229,7 @@ def data_collection_hook(self):
+ "======================================="
)
- # overlap = osc_pars["overlap"]
+ overlap = osc_pars["overlap"]
angle_inc = 90.0
detector.prepare_characterisation(
exp_time, nframes, angle_inc, filepath
@@ -277,58 +271,15 @@ def data_collection_hook(self):
self.collect_characterisation(
start_angle, img_range, nframes, angle_inc, exp_time
)
- # TODO: Add LiveView here
- # os.system("killall albula")
- # os.system("/opt/dectris/albula/4.0/bin/albula "+self.latest_h5_filename +" &")
- # os.system("adxv "+self.latest_h5_filename +" &")
-
- # Open index_html
- os.system("firefox /gpfs/current/processed/index.html")
-
- # Create diffraction snapshots
- for i in range(nframes):
- os.system(
- "python3 /gpfs/local/shared/MXCuBE/hdf5tools/albula_api/generate_image.py --input "
- + self.latest_h5_filename
- + " --output "
- + os.path.join(
- basepath, prefix, "screening_" + str(runno).zfill(3)
- )
- + "/"
- + " --image_number "
- + str(i + 1)
- )
-
else:
self.collect_std_collection(start_angle, stop_angle)
self.generate_xds_template()
- # self.adxv_notify(self.latest_h5_filename)
- # TODO: Add LiveView here
- # os.system("killall albula")
- # os.system("/opt/dectris/albula/4.0/bin/albula "+self.latest_h5_filename +" &")
-
- # Open index_html
- os.system("firefox /gpfs/current/processed/index.html")
-
- # Create diffraction snapshots
- os.system(
- "python3 /gpfs/local/shared/MXCuBE/hdf5tools/albula_api/generate_image.py --input "
- + self.latest_h5_filename
- + " --output "
- + os.path.join(
- basepath, prefix, "rotational_" + str(runno).zfill(3)
- )
- + "/"
- + " --image_number 1"
- )
except RuntimeError:
self.log.error(traceback.format_exc())
finally:
self.acquisition_cleanup()
-
- # self.add_h5_info(self.latest_h5_filename)
- self.trigger_auto_processing()
+ self.trigger_auto_processing()
def collect_std_collection(self, start_angle, stop_angle):
"""
@@ -339,21 +290,28 @@ def collect_std_collection(self, start_angle, stop_angle):
:param stop_angle: The stop_angle parameter is the final angle at which the collection should
stop
"""
+ HWR.beamline.diffractometer.wait_omega()
- self.omega_mv(start_angle, self.default_speed)
+ start_pos = start_angle - self.turnback_time * self.acq_speed
+ stop_pos = stop_angle + self.turnback_time * self.acq_speed
self.log.debug("#COLLECT# Running OMEGA through the std acquisition")
if start_angle <= stop_angle:
self.lower_bound_ch.set_value(start_angle)
self.upper_bound_ch.set_value(stop_angle)
+
else:
self.lower_bound_ch.set_value(stop_angle)
self.upper_bound_ch.set_value(start_angle)
- self.acq_arm_cmd()
- final_pos = stop_angle + self.acq_speed * self.turnback_time
-
- self.omega_mv(final_pos, self.acq_speed)
+ self.omega_mv(start_pos, self.default_speed)
+ self.acq_arm_cmd()
+ self.omega_mv(stop_pos, self.acq_speed)
+ time.sleep(0.5)
+ self.acq_off_cmd()
+ self.acq_window_off_cmd()
+ self.omega_mv(stop_angle, self.acq_speed)
+ HWR.beamline.diffractometer.wait_omega()
def collect_characterisation(
self, start_angle, img_range, nimages, angle_inc, exp_time
@@ -374,34 +332,34 @@ def collect_characterisation(
diffr = HWR.beamline.diffractometer
- self.log.debug("#COLLECT# Running OMEGA through the char acquisition")
+ self.log.debug(
+ "#COLLECT# Running OMEGA through the characteristation acquisition"
+ )
self.omega_mv(start_angle, self.default_speed)
for img_no in range(nimages):
- print("collecting image %s" % img_no)
+ logging.info("collecting image %s" % img_no)
start_at = start_angle + angle_inc * img_no
stop_angle = start_at + img_range * 1.0
- print("collecting image %s, angle %f" % (img_no, start_at))
+
+ logging.info("collecting image %s, angle %f" % (img_no, start_at))
if start_at >= stop_angle:
- init_pos = start_at - self.acq_speed * self.turnback_time
- # init_pos = start_at - 1.5
+ init_pos = start_at
+
else:
- init_pos = start_at + self.acq_speed * self.turnback_time
- # init_pos = start_at + 1.5
- self.omega_mv(init_pos, self.default_speed)
- self.collect_std_collection(start_angle, stop_angle)
+ init_pos = start_at
+
+ self.collect_std_collection(start_at, stop_angle)
- diffr.set_omega_velocity(self.default_speed)
- self.acq_window_off_cmd()
- self.acq_off_cmd()
self.log.debug(
"======= collect_characterisation Waiting ======================================="
)
- # Let adxv know whether it is
- # self.adxv_notify(self.latest_h5_filename,img_no+1)
+ self.log.debug(
+ "======= collect_characterisation Waiting ======================================="
+ )
def adxv_notify(self, image_filename, image_num=1):
"""
@@ -415,8 +373,8 @@ def adxv_notify(self, image_filename, image_num=1):
"""
logging.getLogger("HWR").info(f"ADXV notify {image_filename}")
logging.getLogger("HWR").info(f"ADXV notify {image_num}")
- adxv_host = "localhost" # self.getProperty("adxv_host", "localhost")
- adxv_port = 8100 # int(self.getProperty("adxv_port", "8100"))
+ adxv_host = "localhost"
+ adxv_port = 8100
try:
adxv_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -439,80 +397,132 @@ def acquisition_cleanup(self):
try:
diffr = HWR.beamline.diffractometer
detector = HWR.beamline.detector
- diffr.set_omega_velocity(self.default_speed)
- self.acq_window_off_cmd()
+ detector.stop_acquisition()
+ diffr.wait_omega()
+ # =================
+ # It is probably already finished in a standard collection.
self.acq_off_cmd()
+ self.acq_window_off_cmd()
+ # ==================
+ diffr.set_omega_velocity(self.default_speed)
self.log.debug("#COLLECT# Closing detector cover")
diffr.detector_cover_close(wait=True)
- detector.stop_acquisition()
+
+ # Move omega to 0 at the end
+ self.omega_mv(0, self.default_speed)
+ self.wait_omega()
+
except RuntimeError:
self.log.error(traceback.format_exc())
def add_h5_info(self, h5file):
"""
- The function `add_h5_info` waits for a specified amount of time for a file to appear on disk and
- raises an exception if the file does not appear within the timeout period.
+ Add information to an HDF5 file.
- :param h5file: The `h5file` parameter is the name or path of the H5 file that you want to add
- information to
+ :param h5file: The name or path of the HDF5 file.
"""
self.log.debug("========== Writing H5 info ==============")
- h5file = self.latest_h5_filename
- # wait up to 5 seconds to see the file appear
- start_wait = time.time()
+ # Wait for the HDF5 file to appear with a timeout
+ start_time = time.time()
while not os.path.exists(h5file):
- if time.time() - start_wait > FILE_TIMEOUT:
- raise RuntimeWarning(
- "Cannot add info to H5 file. Timeout waiting for file on disk."
+ if time.time() - start_time > 5:
+ raise IOError(
+ "Cannot add info to HDF5 file. Timeout waiting for file on disk."
)
time.sleep(0.5)
try:
- h5fd = h5py.File(h5file, "r+")
- group = h5fd.create_group("entry/source")
- group.attrs["NX_class"] = np.array("NXsource", dtype="S")
- group.create_dataset("name", data=np.array("PETRA III, DESY", dtype="S"))
- group = h5fd.get("entry/instrument")
- group.create_dataset("name", data=np.array("P11", dtype="S"))
- group = h5fd.create_group("entry/instrument/attenuator")
- group.attrs["NX_class"] = np.array("NXattenuator", dtype="S")
-
- data_set = group.create_dataset(
- "thickness", dtype="f8", data=self.get_filter_thickness()
- )
- data_set.attrs["units"] = np.array("m", dtype="S")
- data_set = group.create_dataset(
- "type", data=np.array("Aluminum", dtype="S")
- )
- data_set = group.create_dataset(
- "attenuator_transmission",
- dtype="f8",
- data=self.get_filter_transmission(),
- )
- # fix rotation axis and detector orientation
- data_set = h5fd.get("entry/sample/transformations/omega")
- data_set.attrs["vector"] = [1.0, 0.0, 0.0]
- data_set = h5fd.get("entry/instrument/detector/module/fast_pixel_direction")
- data_set.attrs["vector"] = [1.0, 0.0, 0.0]
- data_set = h5fd.get("entry/instrument/detector/module/slow_pixel_direction")
- data_set.attrs["vector"] = [0.0, 1.0, 0.0]
- # delete phi angle info to avoid confusion
- nodes = [
- "entry/sample/goniometer/phi",
- "entry/sample/goniometer/phi_end",
- "entry/sample/goniometer/phi_range_average",
- "entry/sample/goniometer/phi_range_total",
- ]
- for node in nodes:
- if node in h5fd:
- del h5fd[node]
- h5fd.close()
-
- except RuntimeError as err_msg:
- self.log.debug("Error while adding info to HDF5 file (%s)" % str(err_msg))
+ with h5py.File(h5file, "r+") as h5fd:
+ # Create or get the 'entry/source' group
+ source_group = self.get_or_create_group(h5fd, "entry/source")
+ source_group.attrs["NX_class"] = np.array("NXsource", dtype="S")
+
+ # Create or get datasets within the 'entry/source' group
+ self.create_or_get_dataset(
+ source_group, "name", np.array("PETRA III, DESY", dtype="S")
+ )
+
+ # Create or get the 'entry/instrument' group
+ instrument_group = self.get_or_create_group(h5fd, "entry/instrument")
+
+ # Create or get datasets within the 'entry/instrument' group
+ self.create_or_get_dataset(
+ instrument_group, "name", np.array("P11", dtype="S")
+ )
+
+ # Create or get the 'entry/instrument/attenuator' group
+ attenuator_group = self.get_or_create_group(
+ instrument_group, "attenuator"
+ )
+ attenuator_group.attrs["NX_class"] = np.array("NXattenuator", dtype="S")
+
+ # Create or get datasets within the 'entry/instrument/attenuator' group
+ self.create_or_get_dataset(
+ attenuator_group, "thickness", self.get_filter_thickness()
+ )
+ self.create_or_get_dataset(
+ attenuator_group, "type", np.array("Aluminum", dtype="S")
+ )
+ self.create_or_get_dataset(
+ attenuator_group,
+ "attenuator_transmission",
+ self.get_filter_transmission(),
+ )
+
+ # Set attributes for certain nodes
+ h5fd["entry/sample/transformations/omega"].attrs["vector"] = [
+ 1.0,
+ 0.0,
+ 0.0,
+ ]
+ h5fd["entry/instrument/detector/module/fast_pixel_direction"].attrs[
+ "vector"
+ ] = [1.0, 0.0, 0.0]
+ h5fd["entry/instrument/detector/module/slow_pixel_direction"].attrs[
+ "vector"
+ ] = [0.0, 1.0, 0.0]
+
+ # Delete unwanted nodes
+ unwanted_nodes = [
+ "entry/sample/goniometer/phi",
+ "entry/sample/goniometer/phi_end",
+ "entry/sample/goniometer/phi_range_average",
+ "entry/sample/goniometer/phi_range_total",
+ ]
+ for node in unwanted_nodes:
+ if node in h5fd:
+ del h5fd[node]
+ except Exception as err_msg:
+ self.log.debug(f"Error while adding info to HDF5 file: {str(err_msg)}")
self.log.debug(traceback.format_exc())
+ def get_or_create_group(self, parent_group, group_name):
+ """
+ Get or create a group within a parent group.
+
+ :param parent_group: The parent group where the new group will be created.
+ :param group_name: The name of the group to get or create.
+ :return: The group object.
+ """
+ if group_name in parent_group:
+ return parent_group[group_name]
+ else:
+ return parent_group.create_group(group_name)
+
+ def create_or_get_dataset(self, group, dataset_name, dataset_data):
+ """
+ Create or get a dataset within a group.
+
+ :param group: The group where the dataset will be created or retrieved.
+ :param dataset_name: The name of the dataset.
+ :param dataset_data: The data to be stored in the dataset.
+ """
+ if dataset_name in group:
+ dataset = group[dataset_name]
+ else:
+ dataset = group.create_dataset(dataset_name, data=dataset_data)
+
def get_filter_thickness(self):
"""
The function `get_filter_thickness` calculates the total thickness of three filters.
@@ -526,7 +536,7 @@ def get_filter_thickness(self):
thickness = int(thick1) + int(thick2) + int(thick3)
- return float(thickness) / 1000000
+ return float(thickness) / 1_000_000
else:
return -1
@@ -670,7 +680,7 @@ def trigger_auto_processing(self, process_event=None, frame_number=None):
mosflm_path_local.split("/gpfs/current/processed/")[1] + "\n"
)
except:
- print(sys.exc_info())
+ logging.info(sys.exc_info())
# create call
# btHelper.user_sshkey = btHelper.user_sshkey.replace("/gpfs/current",triggerUtils.get_beamtime_metadata()[2])
@@ -745,10 +755,6 @@ def trigger_auto_processing(self, process_event=None, frame_number=None):
try:
self.mkdir_with_mode(xdsapp_path_local, mode=0o777)
- # f=open(xdsapp_path_local+"/xdsapp.log", 'a')
- # f.write("xdsapp.log")
- # f.close()
-
self.log.debug(
"=========== XDSAPP ============ XDSAPP directory created"
)
@@ -766,7 +772,7 @@ def trigger_auto_processing(self, process_event=None, frame_number=None):
xdsapp_path_local.split("/gpfs/current/processed/")[1] + "\n"
)
except RuntimeError:
- print(sys.exc_info())
+ logging.info(sys.exc_info())
# create call
ssh = btHelper.get_ssh_command()
@@ -808,115 +814,12 @@ def trigger_auto_processing(self, process_event=None, frame_number=None):
)
)
- # imagepath = self.path.get_path(
- # "/central/beamtime/raw/user/sample/rotational_number/" +
- # "sample_rotational_number_master.h5")
- # processpath = "/beamline/p11/current" + self.path.get_path(
- # "/processed/user/sample/rotational_number/xdsapp")
- #
- #
- #
- #
- # #create processing folder with 0o777
- # self.path.get_path("/beamline/beamtime/processed/user/sample/" +
- # "rotational_number/xdsapp", force=True)
- # #add to datasets.txt for presenterd
- # try:
- # f = open(self.path.get_path(
- # "/beamline/beamtime/processed/datasets.txt"), "a")
- # f.write(self.path.get_path(
- # "user/sample/rotational_number/xdsapp\n").lstrip("/"))
- # f.close()
- # except:
- # print(sys.exc_info())
- #
- # #create call
- # ssh = btHelper.get_ssh_command()
- # sbatch = btHelper.get_sbatch_command(
- # jobname_prefix = "xdsapp",
- # job_dependency = "",
- # logfile_path = processpath + "/xdsapp.log"
- # )
- # cmd = ("/asap3/petra3/gpfs/common/p11/processing/xdsapp_sbatch.sh " + \
- # "{imagepath:s} {processpath:s} {res:f}").format(
- # imagepath = imagepath,
- # processpath = processpath,
- # res = res
- # )
- # print(cmd)
- # os.system("{ssh:s} \"{sbatch:s} --wrap \\\"{cmd:s}\\\"\"".format(
- # ssh = ssh,
- # sbatch = sbatch,
- # cmd = cmd
- # ))
-
- # Test of the autoprocessing as in CC (AG)
- # def trigger_auto_processing(self, process_event=None, frame_number=None):
- # self.log.debug("Triggering auto processing. NOT IMPLEMENTED YET. Direct test from CC.")
- #
- # #creation will fail if beamtime folder, slurm reservation or
- # #bl-fs mount on the compute nodes can not be found
- # try:
- # btHelper = triggerUtils.Trigger()
- # except:
- # print(sys.exc_info())
- # return
- #
- # energy = self.petraThread.currentMonoEnergy / 1000.
- # wavelength = 12.3984 / energy #in Angstrom
- # res = wavelength / (2. * math.sin(0.5 * math.atan(
- # (311. / 2.) / self.parameters["detectordistance"])))
- # frames = self.parameters["frames"]
- # imagepath = self.path.get_path(
- # "/central/beamtime/raw/user/sample/rotational_number/" +
- # "sample_rotational_number_master.h5")
- # processpath = "/beamline/p11/current" + self.path.get_path(
- # "/processed/user/sample/rotational_number/xdsapp")
- #
- # #create processing folder with 0o777
- # self.path.get_path("/beamline/beamtime/processed/user/sample/" +
- # "rotational_number/xdsapp", force=True)
- # #add to datasets.txt for presenterd
- # try:
- # f = open(self.path.get_path(
- # "/beamline/beamtime/processed/datasets.txt"), "a")
- # f.write(self.path.get_path(
- # "user/sample/rotational_number/xdsapp\n").lstrip("/"))
- # f.close()
- # except:
- # print(sys.exc_info())
- #
- # #create call
- # ssh = btHelper.get_ssh_command()
- # sbatch = btHelper.get_sbatch_command(
- # jobname_prefix = "xdsapp",
- # job_dependency = "",
- # logfile_path = processpath + "/xdsapp.log"
- # )
- # cmd = ("/asap3/petra3/gpfs/common/p11/processing/xdsapp_sbatch.sh " + \
- # "{imagepath:s} {processpath:s} {res:f}").format(
- # imagepath = imagepath,
- # processpath = processpath,
- # res = res
- # )
- # print(cmd)
- # os.system("{ssh:s} \"{sbatch:s} --wrap \\\"{cmd:s}\\\"\"".format(
- # ssh = ssh,
- # sbatch = sbatch,
- # cmd = cmd
- # ))
-
def diffractometer_prepare_collection(self):
diffr = HWR.beamline.diffractometer
self.log.debug("#COLLECT# preparing collection ")
if not diffr.is_collect_phase():
self.log.debug("#COLLECT# going to collect phase")
- # # If the pinhole is Down set pinhole to 200
- # if HWR.beamline.diffractometer.pinhole_hwobj.get_position() == "Down":
- # print("Pinhole is down. Setting pinhole to 200.")
- # HWR.beamline.diffractometer.pinhole_hwobj.set_position("200")
- # HWR.beamline.diffractometer.wait_phase()
diffr.goto_collect_phase(wait=True)
self.log.debug("#COLLECT# now in collect phase: %s" % diffr.is_collect_phase())
@@ -1001,7 +904,7 @@ def get_relative_path(self, path1, path2):
if path_1[i] != v__:
break
- parts = ["..",] * (len(path_2) - i)
+ parts = [".."] * (len(path_2) - i)
parts.extend(path_1[i:])
return os.path.join(*parts)
@@ -1043,7 +946,6 @@ def mkdir_with_mode(self, directory, mode):
oldmask = os.umask(000)
os.makedirs(directory, mode=mode)
os.umask(oldmask)
- # self.checkPath(directory,force=True)
self.log.debug("local directory created")
@@ -1053,7 +955,6 @@ def create_directories(self, *args):
"""
for directory in args:
try:
- # os.makedirs(directory)
self.mkdir_with_mode(directory, mode=0o777)
except os.error as err_:
if err_.errno != errno.EEXIST:
@@ -1088,21 +989,12 @@ def check_path(self, path=None, force=False):
try:
os.mkdir(path, mode=0o777)
except RuntimeError:
- print("mkdir failed:", str(sys.exc_info()))
+ logging.info("mkdir failed:", str(sys.exc_info()))
return False
else:
- print("dir not found:", str(sys.exc_info()))
+ logging.info("dir not found:", str(sys.exc_info()))
return False
if not os.access(path, os.W_OK):
- print("dir not writeable:", str(sys.exc_info()))
+ logging.info("dir not writeable:", str(sys.exc_info()))
return False
return path
-
- # def mkdir_with_mode_remote(self, directory, mode):
- # ssh = btHelper.get_ssh_command()
- #
- # os.system("{ssh:s} \"{sbatch:s} --wrap \\\"{cmd:s}\\\"\"".format(
- # ssh = ssh,
- # sbatch = sbatch,
- # cmd = cmd
- # ))
diff --git a/mxcubecore/HardwareObjects/DESY/P11DetectorCover.py b/mxcubecore/HardwareObjects/DESY/P11DetectorCover.py
index e246d7646b..c37e569930 100644
--- a/mxcubecore/HardwareObjects/DESY/P11DetectorCover.py
+++ b/mxcubecore/HardwareObjects/DESY/P11DetectorCover.py
@@ -24,7 +24,7 @@
from mxcubecore.HardwareObjects.abstract.AbstractShutter import AbstractShutter
from mxcubecore.BaseHardwareObjects import HardwareObjectState
-from enum import Enum, unique
+from enum import Enum
__credits__ = ["DESY P11"]
@@ -42,19 +42,9 @@ class P11DetectorCover(AbstractShutter):
default_timeout = 4
move_time_min = 1
- @unique
- class BaseValueEnum(Enum):
- """Defines only the compulsory values."""
- OPEN = "OPEN"
- CLOSED = "CLOSED"
- MOVING = "MOVING"
- UNKNOWN = "UNKNOWN"
-
- VALUES=BaseValueEnum
-
def __init__(self, name):
- super(AbstractShutter, self).__init__(name)
+ super().__init__(name)
self.simulation = False
self.simulated_opened = False
@@ -73,6 +63,7 @@ def __init__(self, name):
def init(self):
"""Initilise the predefined values"""
+ self._initialise_values()
self.simulation = self.get_property("simulation")
self.cmd_timeout = self.get_property("command_timeout", self.default_timeout)
@@ -99,7 +90,13 @@ def init(self):
else:
self.simulated_update()
- super(AbstractShutter, self).init()
+ super().init()
+
+ def _initialise_values(self):
+ """Add additional, known in advance states to VALUES"""
+ values_dict = {item.name: item.value for item in self.VALUES}
+ values_dict.update({"MOVING": "MOVING"})
+ self.VALUES = Enum("ValueEnum", values_dict)
def get_value(self):
if self.simulation:
@@ -196,14 +193,8 @@ def simulated_update(self):
self.update_value(value)
return value
-
- def is_open(self):
- """Check if the shutter is open.
- Returns:
- (bool): True if open, False otherwise.
- """
- return self.get_value() == self.VALUES.OPEN
+ @property
def is_closed(self):
"""Check if the shutter is closed.
Returns:
diff --git a/mxcubecore/HardwareObjects/DESY/P11DetectorDistance.py b/mxcubecore/HardwareObjects/DESY/P11DetectorDistance.py
index e76a389649..0bf8741246 100644
--- a/mxcubecore/HardwareObjects/DESY/P11DetectorDistance.py
+++ b/mxcubecore/HardwareObjects/DESY/P11DetectorDistance.py
@@ -133,7 +133,7 @@ def update_value(self, value=None):
if value is None:
value = self.chan_position.get_value()
- super(P11DetectorDistance, self).update_value(value)
+ super().update_value(value)
def _set_value(self, value):
"""
@@ -141,7 +141,7 @@ def _set_value(self, value):
:param value: float
:return:
"""
- ##if self.chan_state is not None:
+ # if self.chan_state is not None:
# self.update_state(self.STATES.BUSY)
self.chan_position.set_value(value)
diff --git a/mxcubecore/HardwareObjects/DESY/P11EDNACharacterisation.py b/mxcubecore/HardwareObjects/DESY/P11EDNACharacterisation.py
index 7e0eb6c775..ae5c9ac5de 100644
--- a/mxcubecore/HardwareObjects/DESY/P11EDNACharacterisation.py
+++ b/mxcubecore/HardwareObjects/DESY/P11EDNACharacterisation.py
@@ -47,10 +47,27 @@ def __init__(self, name):
self.edna_default_file = None
self.start_edna_command = None
+ def _run_edna(self, input_file, results_file, process_directory):
+ """Starts EDNA"""
+ msg = "Starting EDNA characterisation using xml file %s" % input_file
+ logging.getLogger("queue_exec").info(msg)
+
+ args = (self.start_edna_command, input_file, results_file, process_directory)
+ # subprocess.call("%s %s %s %s" % args, shell=True)
+
+ # Test run DESY
+ self.edna_maxwell(process_directory, input_file, results_file)
+
+ self.result = None
+ if os.path.exists(results_file):
+ self.result = XSDataResultMXCuBE.parseFile(results_file)
+
+ return self.result
+
def edna_maxwell(self, process_directory, inputxml, outputxml):
"""
The function `edna_maxwell` is used to execute a command on a remote cluster using SSH and SBATCH.
-
+
:param process_directory: The `process_directory` parameter is the directory where the processing
will take place. It is a string that represents the path to the directory
:param inputxml: The inputxml parameter is the path to the input XML file that will be used as
@@ -75,21 +92,23 @@ def edna_maxwell(self, process_directory, inputxml, outputxml):
+ "/edna.log",
)
- cmd = (
- "/asap3/petra3/gpfs/common/p11/processing/edna_sbatch.sh "
- + "{inxml:s} {outxml:s} {processpath:s}"
- ).format(
- inxml=inputxml.replace("/gpfs", "/beamline/p11"),
- outxml=outputxml.replace("/gpfs", "/beamline/p11"),
- processpath=process_directory.replace("/gpfs", "/beamline/p11") + "/edna",
- )
-
- self.mkdir_with_mode(process_directory + "/edna", mode=0o777)
-
# Check path conversion
inxml = inputxml.replace("/gpfs", "/beamline/p11")
- outxml = outputxml.replace("/gpfs", "/beamline/p11")
- processpath = process_directory.replace("/gpfs", "/beamline/p11") + "/edna"
+ outxml = outputxml.replace(
+ "/gpfs/current/raw", "/beamline/p11/current/processed"
+ )
+ processpath = (
+ process_directory.replace(
+ "/gpfs/current/raw", "/beamline/p11/current/processed"
+ )
+ + "/edna"
+ )
+ self.mkdir_with_mode(
+ process_directory.replace("/gpfs/current/raw", "/gpfs/current/processed/")
+ + "/edna",
+ mode=0o777,
+ )
+
self.log.debug(
'=======EDNA========== CLUSTER PROCESS DIRECTORY="%s"' % processpath
)
@@ -98,6 +117,12 @@ def edna_maxwell(self, process_directory, inputxml, outputxml):
self.log.debug('=======EDNA========== ssh="%s"' % ssh)
self.log.debug('=======EDNA========== sbatch="%s"' % sbatch)
+
+ cmd = (
+ "/asap3/petra3/gpfs/common/p11/processing/edna_sbatch.sh "
+ + "{inxml:s} {outxml:s} {processpath:s}"
+ ).format(inxml=inxml, outxml=outxml, processpath=processpath)
+
self.log.debug('=======EDNA========== executing process cmd="%s"' % cmd)
self.log.debug(
'=======EDNA========== {ssh:s} "{sbatch:s} --wrap \\"{cmd:s}\\""'.format(
@@ -105,6 +130,12 @@ def edna_maxwell(self, process_directory, inputxml, outputxml):
)
)
+ logging.info(
+ '{ssh:s} "{sbatch:s} --wrap \\"{cmd:s}"\\"'.format(
+ ssh=ssh, sbatch=sbatch, cmd=cmd
+ )
+ )
+
os.system(
'{ssh:s} "{sbatch:s} --wrap \\"{cmd:s}"\\"'.format(
ssh=ssh, sbatch=sbatch, cmd=cmd
@@ -236,15 +267,24 @@ def input_from_params(self, data_collection, char_params):
acquisition_parameters = data_collection.acquisitions[0].acquisition_parameters
path_template = data_collection.acquisitions[0].path_template
+ # Make sure there is a proper path conversion between different mount points
+ logging.info(
+ "======= Characterisation path template ====%s", path_template.directory
+ )
+
image_dir = path_template.directory.replace(
"/gpfs/current", triggerUtils.get_beamtime_metadata()[2]
)
+ logging.info(image_dir)
+
path_str = os.path.join(image_dir, path_template.get_image_file_name())
+ logging.info(path_template.xds_dir)
characterisation_dir = path_template.xds_dir.replace(
"/autoprocessing_", "/characterisation_"
)
+
os.makedirs(characterisation_dir, mode=0o755, exist_ok=True)
for img_num in range(int(acquisition_parameters.num_images)):
@@ -262,7 +302,7 @@ def input_from_params(self, data_collection, char_params):
def mkdir_with_mode(self, directory, mode):
"""
The function creates a directory with a specified mode if it does not already exist.
-
+
:param directory: The "directory" parameter is the path of the directory that you want to
create. It can be an absolute path or a relative path
:param mode: The "mode" parameter in the above code refers to the permissions that will be set
diff --git a/mxcubecore/HardwareObjects/DESY/P11EigerDetector.py b/mxcubecore/HardwareObjects/DESY/P11EigerDetector.py
index 0029d2a672..5bd7db6e24 100644
--- a/mxcubecore/HardwareObjects/DESY/P11EigerDetector.py
+++ b/mxcubecore/HardwareObjects/DESY/P11EigerDetector.py
@@ -18,7 +18,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with MXCuBE. If not, see .
-__copyright__ = """ Copyright © 2010 - 2023 by MXCuBE Collaboration """
+__copyright__ = """ Copyright © 2010 - 2024 by MXCuBE Collaboration """
__license__ = "LGPLv3+"
import gevent
diff --git a/mxcubecore/HardwareObjects/DESY/P11Energy.py b/mxcubecore/HardwareObjects/DESY/P11Energy.py
index 88b6719deb..cda97ccd68 100644
--- a/mxcubecore/HardwareObjects/DESY/P11Energy.py
+++ b/mxcubecore/HardwareObjects/DESY/P11Energy.py
@@ -18,7 +18,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with MXCuBE. If not, see .
-__copyright__ = """ Copyright © 2010 - 2023 by MXCuBE Collaboration """
+__copyright__ = """ Copyright © 2010 - 2024 by MXCuBE Collaboration """
__license__ = "LGPLv3+"
from mxcubecore.HardwareObjects.abstract.AbstractEnergy import AbstractEnergy
@@ -34,7 +34,7 @@ class P11Energy(AbstractEnergy):
_default_energy = 12.0
def __init__(self, name):
- super(P11Energy, self).__init__(name)
+ super().__init__(name)
def init(self):
self.chan_energy = self.get_channel_object("chanEnergy")
diff --git a/mxcubecore/HardwareObjects/DESY/P11FastShutter.py b/mxcubecore/HardwareObjects/DESY/P11FastShutter.py
index 4b4ae4c6e5..8314dde9e4 100644
--- a/mxcubecore/HardwareObjects/DESY/P11FastShutter.py
+++ b/mxcubecore/HardwareObjects/DESY/P11FastShutter.py
@@ -19,7 +19,7 @@
"""P11Shutter"""
-from enum import Enum, unique
+from enum import Enum
from mxcubecore.HardwareObjects.abstract.AbstractShutter import AbstractNState
from mxcubecore.BaseHardwareObjects import HardwareObjectState
@@ -28,48 +28,49 @@
__license__ = "LGPLv3+"
__category__ = "General"
-from enum import Enum, unique
+from enum import Enum
from mxcubecore.HardwareObjects.abstract.AbstractShutter import AbstractShutter
-@unique
-class FastShutterValues(Enum):
- OPEN = "Open"
- CLOSED = "Closed"
-
-
class P11FastShutter(AbstractNState):
"""
P11 BakcLight define interface to Tango backlight at DESY P11
"""
- VALUES = FastShutterValues
-
default_open_time = 8
default_close_time = 3
def __init__(self, name):
- super(AbstractNState, self).__init__(name)
+ super().__init__(name)
self.chan_value = None
def init(self):
"""Initilise the predefined values"""
+ self._initialise_values()
self.chan_value = self.get_channel_object("value")
if self.chan_value is not None:
self.chan_value.connect_signal("update", self.update_fast_shutter)
self.update_fast_shutter(self.chan_value.get_value())
- super(AbstractNState, self).init()
+ super().init()
+
+ def _initialise_values(self):
+ """Add additional, known in advance states to VALUES"""
+ values_dict = {item.name: item.value for item in self.VALUES}
+ values_dict.update({"OPEN": "Open", "CLOSED": "Closed"})
+ self.VALUES = Enum("ValueEnum", values_dict)
def get_value(self):
return self.update_fast_shutter()
+ @property
def is_open(self):
return self.get_value() == self.VALUES.OPEN
+ @property
def is_closed(self):
return self.get_value() == self.VALUES.CLOSED
diff --git a/mxcubecore/HardwareObjects/DESY/P11Flux.py b/mxcubecore/HardwareObjects/DESY/P11Flux.py
new file mode 100644
index 0000000000..d1475ab6f4
--- /dev/null
+++ b/mxcubecore/HardwareObjects/DESY/P11Flux.py
@@ -0,0 +1,72 @@
+#
+# Project: MXCuBE
+# https://github.com/mxcube
+#
+# This file is part of MXCuBE software.
+#
+# MXCuBE is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# MXCuBE is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with MXCuBE. If not, see .
+
+from random import random
+from mxcubecore.HardwareObjects.abstract.AbstractFlux import AbstractFlux
+
+from mxcubecore import HardwareRepository as HWR
+
+__credits__ = ["MXCuBE collaboration"]
+__category__ = "General"
+
+
+class P11Flux(AbstractFlux):
+
+ # default_flux - for initialising mockup
+ default_flux = 5e12
+
+ def __init__(self, name):
+ AbstractFlux.__init__(self, name)
+
+ self.measured_flux_list = []
+ self.measured_flux_dict = {}
+ self.current_flux_dict = {}
+
+ def init(self):
+
+ self.measure_flux()
+
+ def get_value(self):
+ """Get flux at current transmission in units of photons/s"""
+
+ """ FLUX IS CHEETED HERE - NOWERE ELSE!"""
+ return self.current_flux_dict["flux"]
+
+ def measure_flux(self):
+ """Measures intesity"""
+ beam_size = HWR.beamline.beam.get_beam_size()
+ transmission = HWR.beamline.transmission.get_value()
+ flux = self.default_flux * (1 + random())
+
+ self.measured_flux_list = [
+ {
+ "size_x": beam_size[0],
+ "size_y": beam_size[1],
+ "transmission": transmission,
+ "flux": flux,
+ }
+ ]
+
+ self.measured_flux_dict = self.measured_flux_list[0]
+ self.current_flux_dict = self.measured_flux_list[0]
+
+ self.emit(
+ "fluxInfoChanged",
+ {"measured": self.measured_flux_dict, "current": self.current_flux_dict},
+ )
diff --git a/mxcubecore/HardwareObjects/DESY/P11ISPyBClient.py b/mxcubecore/HardwareObjects/DESY/P11ISPyBClient.py
index d1f259cb7a..18aaa89172 100644
--- a/mxcubecore/HardwareObjects/DESY/P11ISPyBClient.py
+++ b/mxcubecore/HardwareObjects/DESY/P11ISPyBClient.py
@@ -26,8 +26,6 @@ def init(self):
"PROPOSAL NUMBER is %s" % self.simulated_prop_number
)
- self.loginType = "user"
-
def update_data_collection(self, mx_collection, wait=False):
mx_collection["beamline_name"] = "P11"
ISPyBClient.update_data_collection(self, mx_collection, wait)
@@ -40,6 +38,10 @@ def store_image(self, image_dict):
self.prepare_image_for_lims(image_dict)
return ISPyBClient.store_image(self, image_dict)
+ def store_robot_action(self, robot_action_dict):
+ # TODO ISPyB is not ready for now. This prevents from error 500 from the server.
+ pass
+
def prepare_collect_for_lims(self, mx_collect_dict):
# Attention! directory passed by reference. modified in place
diff --git a/mxcubecore/HardwareObjects/DESY/P11NanoDiff.py b/mxcubecore/HardwareObjects/DESY/P11NanoDiff.py
index e327c48faa..a23f782fea 100644
--- a/mxcubecore/HardwareObjects/DESY/P11NanoDiff.py
+++ b/mxcubecore/HardwareObjects/DESY/P11NanoDiff.py
@@ -18,7 +18,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with MXCuBE. If not, see .
-__copyright__ = """ Copyright © 2010 - 2023 by MXCuBE Collaboration """
+__copyright__ = """ Copyright © 2010 - 2024 by MXCuBE Collaboration """
__license__ = "LGPLv3+"
import sys
@@ -118,20 +118,20 @@ def init(self):
# using sample_centring module
self.centring_sampx = sample_centring.CentringMotor(
- self.motor_hwobj_dict["sampx"], units="microns",
+ self.motor_hwobj_dict["sampx"], units="microns"
)
self.centring_sampy = sample_centring.CentringMotor(
- self.motor_hwobj_dict["sampy"], units="microns",
+ self.motor_hwobj_dict["sampy"], units="microns"
)
self.centring_phi = sample_centring.CentringMotor(
- self.motor_hwobj_dict["phi"], direction=-1,
+ self.motor_hwobj_dict["phi"], direction=-1
)
self.centring_phiz = sample_centring.CentringMotor(
self.motor_hwobj_dict["phiz"], direction=1, units="microns"
)
self.centring_phiy = sample_centring.CentringMotor(
- self.motor_hwobj_dict["phiy"], direction=1, units="microns",
+ self.motor_hwobj_dict["phiy"], direction=1, units="microns"
)
self.detcover_hwobj = self.get_object_by_role("detector-cover")
@@ -154,7 +154,8 @@ def init(self):
self.update_phase()
self.update_zoom_calibration()
- self.beam_position = self.update_beam_position()
+ # self.beam_position = self.update_beam_position()
+ self.update_beam_position()
def update_beam_position(self):
zoom_hwobj = self.motor_hwobj_dict["zoom"]
@@ -737,9 +738,9 @@ def detector_cover_close(self, wait=True):
def wait_detcover(self, state, timeout=60):
start_time = time.time()
while time.time() - start_time > timeout:
- if state == "open" and self.detcover_hwobj.is_open():
+ if state == "open" and self.detcover_hwobj.is_open:
break
- elif state == "close" and self.detcover_hwobj.is_closed():
+ elif state == "close" and self.detcover_hwobj.is_closed:
break
gevent.sleep(0.5)
@@ -802,8 +803,8 @@ def update_phase(self, value=None):
omega_pos = self.get_omega_position()
- cover_open = self.detcover_hwobj.is_open()
- cover_closed = self.detcover_hwobj.is_closed()
+ cover_open = self.detcover_hwobj.is_open
+ cover_closed = self.detcover_hwobj.is_closed
blight_in = self.backlight_hwobj.is_in()
blight_out = self.backlight_hwobj.is_out()
collim = self.collimator_hwobj.get_position()
diff --git a/mxcubecore/HardwareObjects/DESY/P11Pinhole.py b/mxcubecore/HardwareObjects/DESY/P11Pinhole.py
index dd000b31d5..8710970efa 100644
--- a/mxcubecore/HardwareObjects/DESY/P11Pinhole.py
+++ b/mxcubecore/HardwareObjects/DESY/P11Pinhole.py
@@ -33,7 +33,7 @@
class P11Pinhole(MotorsNPosition):
def __init__(self, name):
- super(P11Pinhole, self).__init__(name)
+ super().__init__(name)
self._config_file = None
@@ -44,7 +44,7 @@ def init(self):
self._config_file = self.get_property("config_file")
- super(P11Pinhole, self).init()
+ super().init()
def load_positions(self):
@@ -57,7 +57,7 @@ def load_positions(self):
names = config["Pinholes"]["pinholesizelist"].split(",")
names[0] = "Down"
- units = ["micron",] * len(names)
+ units = ["micron"] * len(names)
units[0] = ""
posnames = copy.copy(names)
diff --git a/mxcubecore/HardwareObjects/DESY/P11SampleChanger.py b/mxcubecore/HardwareObjects/DESY/P11SampleChanger.py
index 2ec48d57ab..67cc3d47ad 100644
--- a/mxcubecore/HardwareObjects/DESY/P11SampleChanger.py
+++ b/mxcubecore/HardwareObjects/DESY/P11SampleChanger.py
@@ -18,7 +18,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with MXCuBE. If not, see .
-__copyright__ = """ Copyright © 2010 - 2023 by MXCuBE Collaboration """
+__copyright__ = """ Copyright © 2010 - 2024 by MXCuBE Collaboration """
__license__ = "LGPLv3+"
@@ -41,7 +41,7 @@ class P11SampleChanger(SampleChanger):
NO_OF_SAMPLES_IN_BASKET = 16
def __init__(self, *args, **kwargs):
- super(P11SampleChanger, self).__init__(self.__TYPE__, False, *args, **kwargs)
+ super().__init__(self.__TYPE__, False, *args, **kwargs)
def init(self):
self._selected_sample = -1
@@ -205,6 +205,7 @@ def load(self, sample=None, wait=True):
"Sample changer: Sample loaded (total time: %s)"
% (time.time() - self._start_load)
)
+
self.emit("progressStop", ())
return self.get_loaded_sample()
@@ -476,6 +477,7 @@ def _update_selection(self):
# find sample
for s in self.get_sample_list():
+ # print(f"Sample coords = {s.get_coords()}")
if s.get_coords() == (basket, sample):
self.log.debug(" - sample found")
self._set_loaded_sample(s)
diff --git a/mxcubecore/HardwareObjects/DESY/P11Session.py b/mxcubecore/HardwareObjects/DESY/P11Session.py
index fc959c288a..466f875c51 100644
--- a/mxcubecore/HardwareObjects/DESY/P11Session.py
+++ b/mxcubecore/HardwareObjects/DESY/P11Session.py
@@ -18,7 +18,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with MXCuBE. If not, see .
-__copyright__ = """ Copyright © 2010 - 2023 by MXCuBE Collaboration """
+__copyright__ = """ Copyright © 2010 - 2024 by MXCuBE Collaboration """
__license__ = "LGPLv3+"
import os
@@ -41,11 +41,11 @@ class P11Session(Session):
default_archive_folder = "raw"
def __init__(self, *args):
- super(P11Session, self).__init__(*args)
+ super().__init__(*args)
def init(self):
- super(P11Session, self).init()
+ super().init()
self.settings_file = self.get_property("p11_settings_file")
self.operation_mode = self.get_property("mode")
@@ -85,8 +85,19 @@ def info_set_defaults(self):
self.beamtime_info["rootPath"] = PATH_FALLBACK
def is_beamtime_open(self):
- return True
- # return self.is_writable_dir( os.path.join(PATH_BEAMTIME, self.raw_data_folder_name) )
+ self.log.debug("=========== CHECKING IF BEAMTIME ID IS OPEN... ============")
+ if self.is_writable_dir(os.path.join(PATH_BEAMTIME, self.raw_data_folder_name)):
+ self.log.debug(
+ "=========== BEAMTIME IS OPEN (/gpfs/current exists) ============"
+ )
+ else:
+ self.log.debug(
+ "=========== NO BEMTIME ID IS OPEN (check /gpfs/current) ============"
+ )
+
+ return self.is_writable_dir(
+ os.path.join(PATH_BEAMTIME, self.raw_data_folder_name)
+ )
def is_commissioning_open(self):
return self.is_writable_dir(
@@ -111,6 +122,9 @@ def get_current_proposal_number(self):
info = self.get_beamtime_info()
return info["proposalId"]
+ def get_beamtime_info(self):
+ return self.beamtime_info
+
def read_beamtime_info(self):
self.log.debug("=========== READING BEAMTIME INFO ============")
if os.path.exists(PATH_BEAMTIME):
diff --git a/mxcubecore/HardwareObjects/DESY/P11Shutter.py b/mxcubecore/HardwareObjects/DESY/P11Shutter.py
index 3a147822dc..a09382f891 100644
--- a/mxcubecore/HardwareObjects/DESY/P11Shutter.py
+++ b/mxcubecore/HardwareObjects/DESY/P11Shutter.py
@@ -22,6 +22,7 @@
import gevent
import urllib
from mxcubecore.HardwareObjects.abstract.AbstractShutter import AbstractShutter
+import mxcubecore.HardwareObjects.abstract.AbstractShutter as absshut
from mxcubecore.BaseHardwareObjects import HardwareObjectState
from enum import Enum, unique
@@ -40,17 +41,18 @@ class P11Shutter(AbstractShutter):
@unique
class BaseValueEnum(Enum):
- """Defines only the compulsory values."""
- OPEN = "OPEN"
- CLOSED = "CLOSED"
- MOVING = "MOVING"
- UNKNOWN = "UNKNOWN"
-
- VALUES=BaseValueEnum
+ """Defines only the compulsory values."""
+
+ OPEN = "OPEN"
+ CLOSED = "CLOSED"
+ MOVING = "MOVING"
+ UNKNOWN = "UNKNOWN"
+
+ VALUES = BaseValueEnum
def __init__(self, name):
- super(AbstractShutter, self).__init__(name)
+ super().__init__(name)
self.simulation = False
self.simulated_opened = True
@@ -68,6 +70,7 @@ def init(self):
# if simulation is set - open and close will be mere software flags
self.simulation = self.get_property("simulation")
+ self._initialise_values()
if not self.simulation:
url_base = self.get_property("base_url")
@@ -85,7 +88,15 @@ def init(self):
else:
self.simulated_update()
- super(AbstractShutter, self).init()
+ self.update_state(self.STATES.READY)
+
+ super().init()
+
+ def _initialise_values(self):
+ """Add additional, known in advance states to VALUES"""
+ values_dict = {item.name: item.value for item in self.VALUES}
+ values_dict.update({"MOVING": "MOVING"})
+ self.VALUES = Enum("ValueEnum", values_dict)
def get_value(self):
if self.simulation:
@@ -105,25 +116,40 @@ def _set_value(self, value):
if self.simulation:
self.simulated_opened = open_it
self.simulated_moving = True
- gevent.spawn(self.simul_do)
+ self.t1 = gevent.spawn(self.simul_do)
+ self.t1.link(self.do_finish)
+ self.t1.link_exception(self.do_finish_exc)
else:
if open_it:
self.do_open()
else:
self.do_close()
self.cmd_started = time.time()
+ self.log.debug(" ### setting value value for shutter done")
def do_open(self, timeout=3):
+ self.log.debug(" OPENING SHUTTER (web request)")
result = urllib.request.urlopen(self.url_open, None, timeout).readlines()
+ self.log.debug(" OPENING SHUTTER (web request) retured")
def do_close(self, timeout=3):
+ self.log.debug(" CLOSING SHUTTER (web request)")
result = urllib.request.urlopen(self.url_close, None, timeout).readlines()
+ self.log.debug(" CLOSING SHUTTER (web request) retured")
def simul_do(self):
+ self.log.debug("### starting simulated shutter move")
gevent.sleep(1)
self.simulated_moving = False
self.log.debug("### updating simulated shutter")
self.simulated_update()
+ self.log.debug("### ending simulated shutter move")
+
+ def do_finish(self, t=None):
+ self.log.debug("### simulated finished")
+
+ def do_finish_exc(self, exc=None):
+ self.log.debug("### simulated finished with exception")
def update_shutter_state(self, state=None):
"""Updates shutter state
@@ -133,9 +159,13 @@ def update_shutter_state(self, state=None):
if state is None:
state = self.chan_state.get_value()
+ self.log.debug(" SHUTTER state changed")
+
if state[0] == 3:
+ self.log.debug(" P11SHUTTER IS OPEN")
value = self.VALUES.OPEN
else:
+ self.log.debug(" P11SHUTTER IS CLOSED")
value = self.VALUES.CLOSED
# else:
@@ -146,6 +176,7 @@ def update_shutter_state(self, state=None):
self.update_value(value)
+ self.log.debug(" update shutter state done")
return value
def simulated_update(self):
diff --git a/mxcubecore/HardwareObjects/DESY/P11Transmission.py b/mxcubecore/HardwareObjects/DESY/P11Transmission.py
index 9f564a441c..9b929072b5 100644
--- a/mxcubecore/HardwareObjects/DESY/P11Transmission.py
+++ b/mxcubecore/HardwareObjects/DESY/P11Transmission.py
@@ -18,7 +18,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with MXCuBE. If not, see .
-__copyright__ = """ Copyright © 2010 - 2023 by MXCuBE Collaboration """
+__copyright__ = """ Copyright © 2010 - 2024 by MXCuBE Collaboration """
__license__ = "LGPLv3+"
@@ -35,7 +35,7 @@
class P11Transmission(AbstractTransmission):
def __init__(self, name):
- super(P11Transmission, self).__init__(name)
+ super().__init__(name)
self.chan_read_value = None
self.chan_set_value = None
diff --git a/mxcubecore/HardwareObjects/DESY/ValueStateChannel.py b/mxcubecore/HardwareObjects/DESY/ValueStateChannel.py
index f94f640843..fdab0a73e5 100644
--- a/mxcubecore/HardwareObjects/DESY/ValueStateChannel.py
+++ b/mxcubecore/HardwareObjects/DESY/ValueStateChannel.py
@@ -23,7 +23,7 @@
class ValueStateChannel(HardwareObject):
def __init__(self, name):
- super(ValueStateChannel, self).__init__(name)
+ super().__init__(name)
def init(self):