diff --git a/mxcubecore/Command/Sardana.py b/mxcubecore/Command/Sardana.py index 9c70617293..99940f17af 100644 --- a/mxcubecore/Command/Sardana.py +++ b/mxcubecore/Command/Sardana.py @@ -50,9 +50,10 @@ # from mxcubecore.TaskUtils import task try: - from sardana.taurus.core.tango.sardana import registerExtensions from taurus import Device, Attribute import taurus + from taurus.core.tango.enums import DevState + from taurus.core.tango.tangoattribute import TangoAttrValue except Exception: logging.getLogger("HWR").warning("Sardana is not available in this computer.") @@ -191,10 +192,16 @@ def __call__(self, *args, **kwargs): import time self.t0 = time.time() - if self.doorstate in ["ON", "ALARM"]: + if self.doorstate in [DevState.ON, DevState.ALARM]: self.door.runMacro(fullcmd.split()) self.macrostate = SardanaMacro.STARTED self.emit("commandBeginWaitReply", (str(self.name()),)) + + if wait: + logging.getLogger("HWR").debug("... start waiting...") + t = gevent.spawn(end_of_macro, self) + t.get() + logging.getLogger("HWR").debug("... end waiting...") else: logging.getLogger("HWR").error( "%s. Cannot execute. Door is not READY", str(self.name()) @@ -226,29 +233,24 @@ def __call__(self, *args, **kwargs): ) self.emit("commandFailed", (-1, self.name())) - if wait: - logging.getLogger("HWR").debug("... start waiting...") - t = gevent.spawn(end_of_macro, self) - t.get() - logging.getLogger("HWR").debug("... end waiting...") - return def update(self, event): data = event.event[2] try: - if not isinstance(data, PyTango.DeviceAttribute): + if not isinstance(data, PyTango.DeviceAttribute) and \ + not isinstance(data, TangoAttrValue): # Events different than a value changed on attribute. Taurus sends an event with attribute info # logging.getLogger('HWR').debug("==========. Got an event, but it is not an attribute . it is %s" % type(data)) # logging.getLogger('HWR').debug("doorstate event. type is %s" % str(type(data))) return # Handling macro state changed event - doorstate = str(data.value) - logging.getLogger("HWR").debug( - "doorstate changed. it is %s" % str(doorstate) - ) + doorstate = data.rvalue + #logging.getLogger("HWR").debug( + #"doorstate changed. it is %s" % str(doorstate) + #) if doorstate != self.doorstate: self.doorstate = doorstate @@ -256,24 +258,25 @@ def update(self, event): # logging.getLogger('HWR').debug("self.doorstate is %s" % self.canExecute()) self.emit("commandCanExecute", (self.can_execute(),)) - if doorstate in ["ON", "ALARM"]: + if doorstate in [DevState.ON, DevState.ALARM]: # logging.getLogger('HWR').debug("Macroserver ready for commands") self.emit("commandReady", ()) else: # logging.getLogger('HWR').debug("Macroserver busy ") self.emit("commandNotReady", ()) - if self.macrostate == SardanaMacro.STARTED and doorstate == "RUNNING": + if self.macrostate == SardanaMacro.STARTED and \ + doorstate == DevState.RUNNING: # logging.getLogger('HWR').debug("Macro server is running") self.macrostate = SardanaMacro.RUNNING - elif self.macrostate == SardanaMacro.RUNNING and ( - doorstate in ["ON", "ALARM"] + elif self.macrostate == SardanaMacro.RUNNING and (\ + doorstate in [DevState.ON, DevState.ALARM] ): logging.getLogger("HWR").debug("Macro execution finished") self.macrostate = SardanaMacro.DONE self.result = self.door.result self.emit("commandReplyArrived", (self.result, str(self.name()))) - if doorstate == "ALARM": + if doorstate == DevState.ALARM: self.emit("commandAborted", (str(self.name()),)) self._reply_arrived_event.set() elif ( @@ -412,22 +415,23 @@ def init_device(self): return # read information - try: - if taurus.Release.version_info[0] == 3: - ranges = self.attribute.getConfig().getRanges() - if ranges is not None and ranges[0] != "Not specified": - self.info.minval = float(ranges[0]) - if ranges is not None and ranges[-1] != "Not specified": - self.info.maxval = float(ranges[-1]) - elif taurus.Release.version_info[0] > 3: # taurus 4 and beyond - minval, maxval = self.attribute.ranges() - self.info.minval = minval.magnitude - self.info.maxval = maxval.magnitude - except Exception: - import traceback - - logging.getLogger("HWR").info("info initialized. Cannot get limits") - logging.getLogger("HWR").info("%s" % traceback.format_exc()) + if "Position" in str(self.attribute): # RB: quick hack, find a better way to check if this channel is a position channel + try: + if taurus.Release.version_info[0] == 3: + ranges = self.attribute.getConfig().getRanges() + if ranges is not None and ranges[0] != "Not specified": + self.info.minval = float(ranges[0]) + if ranges is not None and ranges[-1] != "Not specified": + self.info.maxval = float(ranges[-1]) + elif taurus.Release.version_info[0] > 3: # taurus 4 and beyond + minval, maxval = self.attribute.getRanges() + self.info.minval = minval.magnitude + self.info.maxval = maxval.magnitude + except Exception: + import traceback + + logging.getLogger("HWR").info("info initialized for Sardana channel %s. Cannot get limits" % self.model) + logging.getLogger("HWR").info("%s" % traceback.format_exc()) # prepare polling # if the polling value is a number set it as the taurus polling period @@ -441,26 +445,58 @@ def init_device(self): def get_value(self): return self._read_value() + def force_get_value(self): + return self._force_read_value() + def set_value(self, new_value): self._write_value(new_value) def _write_value(self, new_value): self.attribute.write(new_value) + #TODO improve this: the magnitude is probably only available for certain channels, and the rvalue for others + # Instead of an exception, an if statement should decide which read method is to be applied, + # and a proper exception should be issued when necessary def _read_value(self): - value = self.attribute.read().value + value = None + if taurus.Release.version_info[0] == 3: + value = self.attribute.read().value + elif taurus.Release.version_info[0] > 3: # taurus 4 and beyond + try: + magnitude = getattr(self.attribute.rvalue, 'magnitude') + value = magnitude + except Exception: + value = self.attribute.rvalue + return value + + def _force_read_value(self): + value = None + if taurus.Release.version_info[0] == 3: # not sure if this works in versions of taurus 3 and below + value = self.attribute.read(cache=False).value + elif taurus.Release.version_info[0] > 3: # taurus 4 and beyond + try: + value = getattr(self.attribute.read(cache=False).rvalue, 'magnitude') + except Exception: + value = self.attribute.rvalue + return value def get_info(self): try: - b = dir(self.attribute) - ( - self.info.minval, - self.info.maxval, - ) = self.attribute._TangoAttribute__attr_config.get_limits() + if taurus.Release.version_info[0] == 3: + ranges = self.attribute.getConfig().getRanges() + if ranges is not None and ranges[0] != "Not specified": + self.info.min_val = float(ranges[0]) + if ranges is not None and ranges[-1] != "Not specified": + self.info.max_val = float(ranges[-1]) + elif taurus.Release.version_info[0] > 3: # taurus 4 and beyond + range = getattr(self.attribute, 'range') + self.info.min_val = range[0].magnitude + self.info.max_val = range[1].magnitude except Exception: import traceback + logging.getLogger("HWR").info("info initialized. Cannot get limits") logging.getLogger("HWR").info("%s" % traceback.format_exc()) return self.info @@ -469,7 +505,14 @@ def update(self, event): data = event.event[2] try: - new_value = data.value + new_value = None + if taurus.Release.version_info[0] == 3: + new_value = data.value + elif taurus.Release.version_info[0] > 3: # taurus 4 and beyond + try: + new_value = data.rvalue.magnitude + except Exception: + new_value = data.rvalue if new_value is None: new_value = self.get_value() diff --git a/mxcubecore/Command/Tango.py b/mxcubecore/Command/Tango.py index f7325697c7..816271e384 100644 --- a/mxcubecore/Command/Tango.py +++ b/mxcubecore/Command/Tango.py @@ -143,10 +143,7 @@ class TangoChannel(ChannelObject): _tangoEventsQueue = queue.Queue() _eventReceivers = {} - if gevent_version < [1, 3, 0]: - _tangoEventsProcessingTimer = getattr(gevent.get_hub().loop, "async")() - else: - _tangoEventsProcessingTimer = gevent.get_hub().loop.async_() + _tangoEventsProcessingTimer = gevent.get_hub().loop.async() # start Tango events processing timer _tangoEventsProcessingTimer.start(process_tango_events) diff --git a/mxcubecore/CommandContainer.py b/mxcubecore/CommandContainer.py index 5a9028eb6f..5a69525cf9 100644 --- a/mxcubecore/CommandContainer.py +++ b/mxcubecore/CommandContainer.py @@ -123,6 +123,10 @@ def connect_signal(self, signalName, callableFunc): except Exception: pass dispatcher.connect(callableFunc, signalName, self) + # RB: do not commit + # The cats_simple_brick doesnt receive the powered signal, + # the following line fixes that, but a better solution needs to be found. + self.emit(signalName, self.get_value()) def disconnect_signal(self, signalName, callableFunc): try: diff --git a/mxcubecore/HardwareObjects/ALBA/ALBAAutoProcessing.py b/mxcubecore/HardwareObjects/ALBA/ALBAAutoProcessing.py deleted file mode 100644 index 8990d358d9..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBAAutoProcessing.py +++ /dev/null @@ -1,216 +0,0 @@ -from xaloc import XalocJob -from XSDataCommon import XSDataFile, XSDataString, XSDataInteger -from XSDataAutoprocv1_0 import XSDataAutoprocInput -from mxcubecore.BaseHardwareObjects import HardwareObject -from PyTango import DeviceProxy -import os -import logging -import math -from datetime import datetime - -from ALBAClusterJob import ALBAEdnaProcJob - -import sys - -sys.path.append("/beamlines/bl13/controls/devel/pycharm/ALBAClusterClient") - - -root = os.environ["POST_PROCESSING_SCRIPTS_ROOT"] -sls_script = os.path.join(root, "gphl/autoproc/autoproc.process.sl") - - -class ALBAAutoProcessing(HardwareObject): - def init(self): - HardwareObject.init(self) - - self.template_dir = self.get_property("template_dir") - var_dsname = self.get_property("variables_ds") - logging.getLogger("HWR").debug( - "ALBAAutoProcessing INIT: var_ds=%s, template_dir=%s" - % (var_dsname, self.template_dir) - ) - self.var_ds = DeviceProxy(var_dsname) - - # input files for standard collection auto processing - def create_input_files(self, xds_dir, mosflm_dir, dc_pars): - - fileinfo = dc_pars["fileinfo"] - osc_seq = dc_pars["oscillation_sequence"][0] - - prefix = fileinfo["prefix"] - runno = fileinfo["run_number"] - - exp_time = osc_seq["exposure_time"] - - start_angle = osc_seq["start"] - nb_images = osc_seq["number_of_images"] - start_img_num = osc_seq["start_image_number"] - angle_increment = osc_seq["range"] - - wavelength = osc_seq.get("wavelength", 0) - - xds_template_name = "XDS_TEMPLATE.INP" - mosflm_template_name = "mosflm_template.dat" - - xds_template_path = os.path.join(self.template_dir, xds_template_name) - mosflm_template_path = os.path.join(self.template_dir, mosflm_template_name) - - xds_file = os.path.join(xds_dir, "XDS.INP") - mosflm_file = os.path.join(mosflm_dir, "mosflm.dat") - - t = datetime.now() - - # PREPARE VARIABLES - detsamdis = self.var_ds.detsamdis - beamx, beamy = self.var_ds.beamx, self.var_ds.beamy - - mbeamx, mbeamy = beamy * 0.172, beamx * 0.172 - - datarangestartnum = start_img_num - datarangefinishnum = start_img_num + nb_images - 1 - backgroundrangestartnum = start_img_num - spotrangestartnum = start_img_num - if angle_increment != 0: - minimumrange = int(round(20 / angle_increment)) - elif angle_increment == 0: - minimumrange = 1 - if nb_images >= minimumrange: - backgroundrangefinishnum = start_img_num + minimumrange - 1 - if nb_images >= minimumrange: - spotrangefinishnum = start_img_num + minimumrange - 1 - if nb_images < minimumrange: - backgroundrangefinishnum = start_img_num + nb_images - 1 - if nb_images < minimumrange: - spotrangefinishnum = start_img_num + nb_images - 1 - - testlowres = 8.0 - largestvector = ( - 0.172 - * ((max(beamx, 2463 - beamx)) ** 2 + (max(beamy, 2527 - beamy)) ** 2) ** 0.5 - ) - testhighres = round( - wavelength / (2 * math.sin(0.5 * math.atan(largestvector / detsamdis))), 2 - ) - lowres = 50.0 - highres = testhighres - datafilename = prefix + "_" + str(runno) + "_????" - mdatafilename = prefix + "_" + str(runno) + "_####.cbf" - seconds = 5 * exp_time - - if angle_increment < 1 and not angle_increment == 0: - seconds = 5 * exp_time / angle_increment - - # DEFINE SG/UNIT CELL - spacegroupnumber = "" - unitcellconstants = "" - - datapath_dir = os.path.abspath(xds_file).replace("PROCESS_DATA", "RAW_DATA") - datapath_dir = os.path.dirname(os.path.dirname(datapath_dir)) + os.path.sep - - # CREATE XDS.INP FILE - xds_templ = open(xds_template_path, "r").read() - - xds_templ = xds_templ.replace("###BEAMX###", str(round(beamx, 2))) - xds_templ = xds_templ.replace("###BEAMY###", str(round(beamy, 2))) - xds_templ = xds_templ.replace("###DETSAMDIS###", str(round(detsamdis, 2))) - xds_templ = xds_templ.replace("###ANGLEINCREMENT###", str(angle_increment)) - xds_templ = xds_templ.replace("###WAVELENGTH###", str(wavelength)) - xds_templ = xds_templ.replace("###DATARANGESTARTNUM###", str(datarangestartnum)) - xds_templ = xds_templ.replace( - "###DATARANGEFINISHNUM###", str(datarangefinishnum) - ) - xds_templ = xds_templ.replace( - "###BACKGROUNDRANGESTART###", str(backgroundrangestartnum) - ) - xds_templ = xds_templ.replace( - "###BACKGROUNDRANGEFINISHNUM###", str(backgroundrangefinishnum) - ) - xds_templ = xds_templ.replace("###SPOTRANGESTARTNUM###", str(spotrangestartnum)) - xds_templ = xds_templ.replace( - "###SPOTRANGEFINISHNUM###", str(spotrangefinishnum) - ) - xds_templ = xds_templ.replace("###TESTLOWRES###", str(testlowres)) - xds_templ = xds_templ.replace("###TESTHIGHRES###", str(testhighres)) - xds_templ = xds_templ.replace("###LOWRES###", str(lowres)) - xds_templ = xds_templ.replace("###HIGHRES###", str(highres)) - xds_templ = xds_templ.replace("###DIRECTORY###", str(datapath_dir)) - xds_templ = xds_templ.replace("###FILENAME###", str(datafilename)) - xds_templ = xds_templ.replace("###SECONDS###", str(int(seconds))) - xds_templ = xds_templ.replace( - "###LYSOZYME_SPACE_GROUP_NUMBER###", str(spacegroupnumber) - ) - xds_templ = xds_templ.replace( - "###LYSOZYME_UNIT_CELL_CONSTANTS###", str(unitcellconstants) - ) - - open(xds_file, "w").write(xds_templ) - - # CREATE MOSFLM.DAT FILE - - mosflm_templ = open(mosflm_template_path, "r").read() - - mosflm_templ = mosflm_templ.replace("###DETSAMDIS###", str(round(detsamdis, 2))) - mosflm_templ = mosflm_templ.replace("###BEAMX###", str(round(mbeamx, 2))) - mosflm_templ = mosflm_templ.replace("###BEAMY###", str(round(mbeamy, 2))) - mosflm_templ = mosflm_templ.replace("###DIRECTORY###", str(datapath_dir)) - mosflm_templ = mosflm_templ.replace("###FILENAME###", str(mdatafilename)) - mosflm_templ = mosflm_templ.replace("###WAVELENGTH###", str(wavelength)) - mosflm_templ = mosflm_templ.replace( - "###DATARANGESTARTNUM###", str(datarangestartnum) - ) - - open(mosflm_file, "w").write(mosflm_templ) - - # CREATE EDNAPROC XML FILE - collection_id = dc_pars["collection_id"] - output_dir = dc_pars["ednaproc_dir"] - - ednaproc_input_file = os.path.join( - output_dir, "EDNAprocInput_%d.xml" % collection_id - ) - - ednaproc_input = XSDataAutoprocInput() - - input_file = XSDataFile() - path = XSDataString() - path.set_value(xds_file) - input_file.setPath(path) - - ednaproc_input.setInput_file(input_file) - ednaproc_input.setData_collection_id(XSDataInteger(collection_id)) - - # output_dir = XSDataFile() - # outpath = XSDataString() - # outpath.set_value(output_dir) - # output_dir.setPath(path) - - # ednaproc_input.setOutput_directory( output_dir ) - - ednaproc_input.exportToFile(ednaproc_input_file) - - self.input_file = ednaproc_input_file - - # trigger auto processing for standard collection - def trigger_auto_processing(self, dc_pars): - logging.getLogger("HWR").debug( - " ALBAAutoProcessing. triggering auto processing." - ) - - dc_id = dc_pars["collection_id"] - output_dir = dc_pars["ednaproc_dir"] - - logging.getLogger("HWR").debug(" - collection_id = %s " % dc_id) - logging.getLogger("HWR").debug(" - output_dir = %s " % output_dir) - - job = ALBAEdnaProcJob() - input_file = self.input_file # TODO - - job.run(dc_id, input_file, output_dir) - - -def test_hwo(hwo): - ofile = "/tmp/edna/edna_result" - odir = "/tmp/edna" - test_input_file = "/beamlines/bl13/projects/cycle2018-I/2018012551-bcalisto/mx2018012551/DATA/20180131/PROCESS_DATA/characterisation_ref-Thrombin-TB-TTI1_A_run1_1/EDNAInput_2004391.xml" - result = hwo.run_edna(test_input_file, ofile, odir) - print(result) diff --git a/mxcubecore/HardwareObjects/ALBA/ALBABeamInfo.py b/mxcubecore/HardwareObjects/ALBA/ALBABeamInfo.py deleted file mode 100644 index bcc29ef5c8..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBABeamInfo.py +++ /dev/null @@ -1,198 +0,0 @@ -""" -[Name] BeamInfo - -[Description] -BeamInfo hardware object is used to define final beam size and shape. -It can include aperture, slits and/or other beam definer (lenses or other eq.) - -[Emited signals] -beamInfoChanged -beamPosChanged - -[Included Hardware Objects] ------------------------------------------------------------------------ -| name | signals | functions ------------------------------------------------------------------------ - aperture_hwobj apertureChanged - slits_hwobj - beam_definer_hwobj ------------------------------------------------------------------------ -""" - -import logging -from mxcubecore.BaseHardwareObjects import Equipment - - -class ALBABeamInfo(Equipment): - """ - Description: - """ - - def __init__(self, *args): - """ - Descrip. : - """ - Equipment.__init__(self, *args) - - self.aperture_hwobj = None - self.slits_hwobj = None - - self.beam_size_slits = None - self.beam_size_aperture = None - self.beam_size_definer = None - self.beam_position = None - self.beam_info_dict = None - self.default_beam_divergence = None - - def init(self): - """ - Descript. : - """ - self.beam_size_slits = [9999, 9999] - self.beam_size_aperture = [9999, 9999] - self.beam_size_definer = [9999, 9999] - - self.beam_position = [0, 0] - self.beam_info_dict = {} - - self.beam_width_chan = self.get_channel_object("BeamWidth") - self.beam_height_chan = self.get_channel_object("BeamHeight") - self.beam_posx_chan = self.get_channel_object("BeamPositionHorizontal") - self.beam_posy_chan = self.get_channel_object("BeamPositionVertical") - - self.beam_height_chan.connect_signal("update", self.beam_height_changed) - self.beam_width_chan.connect_signal("update", self.beam_width_changed) - self.beam_posx_chan.connect_signal("update", self.beam_posx_changed) - self.beam_posy_chan.connect_signal("update", self.beam_posy_changed) - - # divergence can be added as fixed properties in xml - default_beam_divergence_vertical = None - default_beam_divergence_horizontal = None - - try: - default_beam_divergence_vertical = int( - self.get_property("beam_divergence_vertical") - ) - default_beam_divergence_horizontal = int( - self.get_property("beam_divergence_horizontal") - ) - except Exception: - pass - - self.default_beam_divergence = [ - default_beam_divergence_horizontal, - default_beam_divergence_vertical, - ] - - def connect_notify(self, *args): - self.evaluate_beam_info() - self.re_emit_values() - - def get_beam_divergence_hor(self): - """ - Descript. : - """ - return self.default_beam_divergence[0] - - def get_beam_divergence_ver(self): - """ - Descript. : - """ - return self.default_beam_divergence[1] - - def get_beam_position(self): - """ - Descript. : - Arguments : - Return : - """ - self.beam_position = ( - self.beam_posx_chan.get_value(), - self.beam_posy_chan.get_value(), - ) - return self.beam_position - - def get_slits_gap(self): - return None, None - - def set_beam_position(self, beam_x, beam_y): - """ - Descript. : - Arguments : - Return : - """ - self.beam_position = (beam_x, beam_y) - - def get_beam_info(self): - """ - Descript. : - Arguments : - Return : - """ - return self.evaluate_beam_info() - - def get_beam_size(self): - """ - Descript. : returns beam size in millimeters - Return : list with two integers - """ - self.evaluate_beam_info() - return self.beam_info_dict["size_x"], self.beam_info_dict["size_y"] - - def get_beam_shape(self): - """ - Descript. : - Arguments : - Return : - """ - return self.beam_info_dict["shape"] - - def beam_width_changed(self, value): - self.beam_info_dict["size_x"] = value - self.re_emit_values() - - def beam_height_changed(self, value): - self.beam_info_dict["size_y"] = value - self.re_emit_values() - - def beam_posx_changed(self, value): - self.beam_position["x"] = value - self.re_emit_values() - - def beam_posy_changed(self, value): - self.beam_position["y"] = value - self.re_emit_values() - - def evaluate_beam_info(self): - """ - Descript. : called if aperture, slits or focusing has been changed - Return : dictionary,{size_x:0.1, size_y:0.1, shape:"rectangular"} - """ - - self.beam_info_dict["size_x"] = self.beam_width_chan.get_value() / 1000.0 - self.beam_info_dict["size_y"] = self.beam_height_chan.get_value() / 1000.0 - self.beam_info_dict["shape"] = "rectangular" - - return self.beam_info_dict - - def re_emit_values(self): - """ - Descript. : - Arguments : - Return : - """ - logging.getLogger("HWR").debug(" emitting beam info") - if ( - self.beam_info_dict["size_x"] != 9999 - and self.beam_info_dict["size_y"] != 9999 - ): - self.emit( - "beamSizeChanged", - ((self.beam_info_dict["size_x"], self.beam_info_dict["size_y"]),), - ) - self.emit("beamInfoChanged", (self.beam_info_dict,)) - - -def test_hwo(hwo): - print(hwo.get_beam_info()) - print(hwo.get_beam_position()) diff --git a/mxcubecore/HardwareObjects/ALBA/ALBACalibration.py b/mxcubecore/HardwareObjects/ALBA/ALBACalibration.py deleted file mode 100644 index fe987fa070..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBACalibration.py +++ /dev/null @@ -1,84 +0,0 @@ -# -# 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 . - -""" -[Name] -ALBACalibration - -[Description] -HwObj used to grab the zoom/pixel size calibration from -PySignal simulator (TangoDS). - - -Example Hardware Object XML file : -================================== - - Calibration - bl13/ct/variables - OAV_PIXELSIZE_X - OAV_PIXELSIZE_Y - 200 - 0.001 - -""" - -from mxcubecore import HardwareRepository as HWR -from mxcubecore import BaseHardwareObjects -import logging - -__author__ = "Jordi Andreu" -__credits__ = ["MXCuBE collaboration"] - -__version__ = "2.2." -__maintainer__ = "Jordi Andreu" -__email__ = "jandreu[at]cells.es" -__status__ = "Draft" - - -class ALBACalibration(BaseHardwareObjects.Device): - def __init__(self, name): - BaseHardwareObjects.Device.__init__(self, name) - - def init(self): - - self.calibx = self.get_channel_object("calibx") - self.caliby = self.get_channel_object("caliby") - - if self.calibx is not None and self.caliby is not None: - logging.getLogger().info("Connected to pixel size calibration channels") - - def getCalibration(self): - calibx = self.calibx.get_value() - caliby = self.caliby.get_value() - logging.getLogger().debug( - "Returning calibration: x=%s, y=%s" % (calibx, caliby) - ) - return [calibx, caliby] - - -def test(): - hwr = HWR.get_hardware_repository() - hwr.connect() - - calib = hwr.get_hardware_object("/calibration") - print("Calibration is: ", calib.getCalibration()) - - -if __name__ == "__main__": - test() diff --git a/mxcubecore/HardwareObjects/ALBA/ALBACats.py b/mxcubecore/HardwareObjects/ALBA/ALBACats.py deleted file mode 100644 index b292f2deff..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBACats.py +++ /dev/null @@ -1,674 +0,0 @@ -from __future__ import print_function - -from mxcubecore.HardwareObjects.Cats90 import ( - Cats90, - SampleChangerState, - TOOL_SPINE, -) - -import logging -import time -import gevent - -TIMEOUT = 3 - - -class ALBACats(Cats90): - """ - Main class used @ ALBA to integrate the CATS-IRELEC sample changer. - """ - - def __init__(self, *args): - Cats90.__init__(self, *args) - - def init(self): - Cats90.init(self) - - self.shifts_channel = self.get_channel_object("shifts") - self.phase_channel = self.get_channel_object("phase") - - self.go_transfer_cmd = self.get_command_object("go_transfer") - self.go_sampleview_cmd = self.get_command_object("go_sampleview") - self.super_abort_cmd = self.get_command_object("super_abort") - self.super_state_channel = self.get_channel_object("super_state") - - self.auto_prepare_diff = self.get_property("auto_prepare_diff") - self.detdist_position_channel = self.get_channel_object("detdist_position") - self.detdist_saved = None - - self._cmdLoadHT = self.get_command_object("_cmdLoadHT") - self._cmdChainedLoadHT = self.get_command_object("_cmdChainedLoadHT") - self._cmdUnloadHT = self.get_command_object("_cmdUnloadHT") - - self._chnPathSafe = self.get_channel_object("_chnPathSafe") - - if self._chnPathRunning is not None: - self._chnPathRunning.connect_signal("update", self._update_running_state) - - if self._chnPowered is not None: - self._chnPowered.connect_signal("update", self._update_powered_state) - - def is_ready(self): - """ - Returns a boolean value indicating is the sample changer is ready for operation. - - @return: boolean - """ - return ( - self.state == SampleChangerState.Ready - or self.state == SampleChangerState.Loaded - or self.state == SampleChangerState.Charging - or self.state == SampleChangerState.StandBy - or self.state == SampleChangerState.Disabled - ) - - def diff_send_transfer(self): - """ - Checks if beamline supervisor is in TRANSFER phase (i.e. sample changer in TRANSFER phase too). - If is not the case, It sends the sample changer to TRANFER phase. - Returns a boolean value indication if the sample changer is in TRANSFER phase. - - @return: boolean - """ - if self.read_super_phase().upper() == "TRANSFER": - logging.getLogger("user_level_log").error( - "Supervisor is already in transfer phase" - ) - return True - - self.go_transfer_cmd() - ret = self._wait_phase_done("TRANSFER") - return ret - - def diff_send_sampleview(self): - """ - Checks if beamline supervisor is in SAMPLE phase (i.e. sample changer in SAMPLE phase too). - If is not the case, It sends the sample changer to SAMPLE phase. - Returns a boolean value indication if the sample changer is in SAMPLE phase. - - @return: boolean - """ - if self.read_super_phase().upper() == "SAMPLE": - logging.getLogger("user_level_log").error( - "Supervisor is already in sample view phase" - ) - return True - - t0 = time.time() - while True: - state = str(self.super_state_channel.get_value()) - if str(state) == "ON": - break - - if (time.time() - t0) > TIMEOUT: - logging.getLogger("user_level_log").error( - "Supervisor timeout waiting for ON state. Returning" - ) - return False - - time.sleep(0.1) - - self.go_sampleview_cmd() - ret = self._wait_phase_done("SAMPLE") - return ret - - def _wait_super_ready(self): - while True: - state = str(self.super_state_channel.get_value()) - if state == "ON": - logging.getLogger("user_level_log").error( - "Supervisor is in ON state. Returning" - ) - break - - def _wait_phase_done(self, final_phase): - """ - Method to wait a phase change. When supervisor reaches the final phase, the diffracometer - returns True. - - @final_phase: target phase - @return: boolean - """ - while True: - state = str(self.super_state_channel.get_value()) - if state == "ON": - logging.getLogger("user_level_log").error( - "Supervisor is in ON state. Returning" - ) - break - elif str(state) != "MOVING": - logging.getLogger("user_level_log").error( - "Supervisor is in a funny state %s" % str(state) - ) - return False - - logging.getLogger("HWR").debug("Supervisor waiting to finish phase change") - time.sleep(0.2) - - time.sleep(0.1) - - if self.read_super_phase().upper() != final_phase: - logging.getLogger("user_level_log").error( - "Supervisor is not yet in %s phase. Aborting load" % final_phase - ) - return False - else: - return True - - def save_detdist_position(self): - self.detdist_saved = self.detdist_position_channel.get_value() - logging.getLogger("user_level_log").error( - "Saving current det.distance (%s)" % self.detdist_saved - ) - - def restore_detdist_position(self): - if abs(self.detdist_saved - self.detdist_position_channel.get_value()) >= 0.1: - logging.getLogger("user_level_log").error( - "Restoring det.distance to %s" % self.detdist_saved - ) - self.detdist_position_channel.set_value(self.detdist_saved) - time.sleep(0.4) - self._wait_super_ready() - - def read_super_phase(self): - """ - Returns supervisor phase (CurrentPhase attribute from Beamline Supervisor Tango DS) - - @return: str - """ - return self.phase_channel.get_value() - - def load(self, sample=None, wait=False, wash=False): - """ - Loads a sample. Overides to include ht basket. - - @sample: sample to load. - @wait: - @wash: wash dring the load opearation. - @return: - """ - - logging.getLogger("HWR").debug( - "Loading sample %s / type(%s)" % (sample, type(sample)) - ) - - ret, msg = self._check_coherence() - if not ret: - raise Exception(msg) - - sample_ht = self.is_ht_sample(sample) - - if not sample_ht: - sample = self._resolve_component(sample) - self.assert_not_charging() - use_ht = False - else: - sample = sample_ht - use_ht = True - - if self.has_loaded_sample(): - if (wash is False) and self.get_loaded_sample() == sample: - raise Exception( - "The sample " + sample.get_address() + " is already loaded" - ) - else: - # Unload first / do a chained load - pass - - return self._execute_task( - SampleChangerState.Loading, wait, self._do_load, sample, None, use_ht - ) - - def unload(self, sample_slot=None, wait=False): - """ - Unload the sample. If sample_slot=None, unloads to the same slot the sample was loaded from. - - @sample_slot: - @wait: - @return: - """ - sample_slot = self._resolve_component(sample_slot) - - self.assert_not_charging() - - # In case we have manually mounted we can command an unmount - if not self.has_loaded_sample(): - raise Exception("No sample is loaded") - - return self._execute_task( - SampleChangerState.Unloading, wait, self._do_unload, sample_slot - ) - - # TODO: this overides identical method from Cats90 - def is_powered(self): - return self._chnPowered.get_value() - - # TODO: this overides identical method from Cats90 - def is_path_running(self): - return self._chnPathRunning.get_value() - - # TODO: this overides method from AbstractSampleChanger - # def has_loaded_sample(self): # not used. to use it remove _ - # return self._chnSampleIsDetected.get_value() - - def _update_running_state(self, value): - """ - Emits signal with new Running State - - @value: New running state - """ - self.emit("runningStateChanged", (value,)) - - def _update_powered_state(self, value): - """ - Emits signal with new Powered State - - @value: New powered state - """ - self.emit("powerStateChanged", (value,)) - - def _do_load(self, sample=None, shifts=None, use_ht=False): - """ - Loads a sample on the diffractometer. Performs a simple put operation if the diffractometer is empty, and - a sample exchange (unmount of old + mount of new sample) if a sample is already mounted on the diffractometer. - Overides Cats90 method. - - @sample: sample to load. - @shifts: mounting point offsets. - @use_ht: mount a sample from hot tool. - """ - if not self._chnPowered.get_value(): - self._cmdPowerOn() # try switching power on - - current_tool = self.get_current_tool() - - self.save_detdist_position() - ret = self.diff_send_transfer() - - if ret is False: - logging.getLogger("user_level_log").error( - "Supervisor cmd transfer phase returned an error." - ) - self._update_state() # remove transient states like Loading. Reflect hardware state - raise Exception( - "CATS cannot get to transfer phase. Aborting sample changer operation." - ) - - gevent.sleep(3) - if not self._chnPowered.get_value(): - raise Exception( - "CATS power is not enabled. Please switch on arm power before transferring samples." - ) - - # obtain mounting offsets from diffr - shifts = self._get_shifts() - - if shifts is None: - xshift, yshift, zshift = ["0", "0", "0"] - else: - xshift, yshift, zshift = map(str, shifts) - - # get sample selection - selected = self.get_selected_sample() - - logging.getLogger("HWR").debug( - " ==========CATS=== selected sample is %s (prev %s)" - % (str(selected), str(sample)) - ) - - if not use_ht: - if sample is not None: - if sample != selected: - self._do_select(sample) - selected = self.get_selected_sample() - else: - if selected is not None: - sample = selected - else: - raise Exception("No sample selected") - else: - selected = None - - # some cancel cases - if ( - not use_ht - and self.has_loaded_sample() - and selected == self.get_loaded_sample() - ): - self._update_state() # remove transient states like Loading. Reflect hardware state - raise Exception( - "The sample " - + str(self.get_loaded_sample().get_address()) - + " is already loaded" - ) - - if not self.has_loaded_sample() and self.cats_sample_on_diffr() == 1: - logging.getLogger("HWR").warning( - " ==========CATS=== sample on diffr, loading aborted" - ) - self._update_state() # remove transient states like Loading. Reflect hardware state - raise Exception( - "The sample " - + str(self.get_loaded_sample().get_address()) - + " is already loaded" - ) - return - - if self.cats_sample_on_diffr() == -1: - self._update_state() # remove transient states like Loading. Reflect hardware state - raise Exception( - "Conflicting info between diffractometer and on-magnet detection. Consider 'Clear'" - ) - return - - # end some cancel cases - - # if load_ht - loaded_ht = self.is_loaded_ht() - - # - # Loading HT sample - # - if use_ht: # loading HT sample - - if loaded_ht == -1: # has loaded but it is not HT - # first unmount (non HT) - logging.getLogger("HWR").warning( - " ==========CATS=== mix load/unload dewar vs HT (NOT IMPLEMENTED YET)" - ) - return - - argin = ["2", str(sample), "0", "0", xshift, yshift, zshift] - logging.getLogger("HWR").warning( - " ==========CATS=== about to load HT. %s" % str(argin) - ) - if loaded_ht == 1: # has ht loaded - cmd_ok = self._execute_server_task( - self._cmdChainedLoadHT, argin, waitsafe=True - ) - else: - cmd_ok = self._execute_server_task( - self._cmdLoadHT, argin, waitsafe=False - ) - - # - # Loading non HT sample - # - else: - if loaded_ht == 1: # has an HT sample mounted - # first unmount HT - logging.getLogger("HWR").warning( - " ==========CATS=== mix load/unload dewar vs HT (NOT IMPLEMENTED YET)" - ) - return - - # calculate CATS specific lid/sample number - # lid = ((selected.get_basket_no() - 1) / 3) + 1 - # sample = (((selected.get_basket_no() - 1) % 3) * 10) + selected.get_vial_no() - - basketno = selected.get_basket_no() - sampleno = selected.get_vial_no() - - lid, sample = self.basketsample_to_lidsample(basketno, sampleno) - tool = self.tool_for_basket(basketno) - stype = self.get_cassette_type(basketno) - - if tool != current_tool: - logging.getLogger("HWR").warning( - " ==========CATS=== changing tool from %s to %s" - % (current_tool, tool) - ) - changing_tool = True - else: - changing_tool = False - - # we should now check basket type on diffr to see if tool is different... - # then decide what to do - - if shifts is None: - xshift, yshift, zshift = ["0", "0", "0"] - else: - xshift, yshift, zshift = map(str, shifts) - - # prepare argin values - argin = [ - str(tool), - str(lid), - str(sample), - str(stype), - "0", - xshift, - yshift, - zshift, - ] - - if tool == 2: - read_barcode = ( - self.read_datamatrix and self._cmdChainedLoadBarcode is not None - ) - else: - if self.read_datamatrix: - logging.getLogger("HWR").warning( - " ==========CATS=== reading barcode only possible with spine pucks" - ) - read_barcode = False - - if loaded_ht == -1: # has a loaded but it is not an HT - - if changing_tool: - raise Exception( - "This operation requires a tool change. You should unload sample first" - ) - - if read_barcode: - logging.getLogger("HWR").warning( - " ==========CATS=== chained load sample (barcode), sending to cats: %s" - % argin - ) - cmd_ok = self._execute_server_task( - self._cmdChainedLoadBarcode, argin, waitsafe=True - ) - else: - logging.getLogger("HWR").warning( - " ==========CATS=== chained load sample, sending to cats: %s" - % argin - ) - cmd_ok = self._execute_server_task( - self._cmdChainedLoad, argin, waitsafe=True - ) - elif loaded_ht == 0: - if read_barcode: - logging.getLogger("HWR").warning( - " ==========CATS=== load sample (barcode), sending to cats: %s" - % argin - ) - cmd_ok = self._execute_server_task( - self._cmdLoadBarcode, argin, waitsafe=True - ) - else: - logging.getLogger("HWR").warning( - " ==========CATS=== load sample, sending to cats: %s" % argin - ) - cmd_ok = self._execute_server_task( - self._cmdLoad, argin, waitsafe=True - ) - - if not cmd_ok: - logging.getLogger("HWR").info(" LOAD Command failed on device server") - elif self.auto_prepare_diff and not changing_tool: - logging.getLogger("HWR").info( - " AUTO_PREPARE_DIFF (On) sample changer is in safe state... preparing diff now" - ) - # ret = self.diff_send_sampleview() - self.go_sampleview_cmd() - logging.getLogger("HWR").info(" restoring detector distance") - self.restore_detdist_position() - self._wait_phase_done("SAMPLE") - else: - logging.getLogger("HWR").info( - " AUTO_PREPARE_DIFF (Off) sample loading done / or changing tool (%s)" - % changing_tool - ) - - # load commands are executed until path is safe. Then we have to wait for - # path to be finished - self._wait_device_ready() - - def _do_unload(self, sample_slot=None, shifts=None): - """ - Unloads a sample from the diffractometer. - Overides Cats90 method. - - @sample_slot: - @shifts: mounting position - """ - if not self._chnPowered.get_value(): - self._cmdPowerOn() # try switching power on - - ret = self.diff_send_transfer() - - if ret is False: - logging.getLogger("user_level_log").error( - "Supervisor cmd transfer phase returned an error." - ) - return - - shifts = self._get_shifts() - - if sample_slot is not None: - self._do_select(sample_slot) - - loaded_ht = self.is_loaded_ht() - - if shifts is None: - xshift, yshift, zshift = ["0", "0", "0"] - else: - xshift, yshift, zshift = map(str, shifts) - - loaded_lid = self._chnLidLoadedSample.get_value() - loaded_num = self._chnNumLoadedSample.get_value() - - if loaded_lid == -1: - logging.getLogger("HWR").warning( - " ==========CATS=== unload sample, no sample mounted detected" - ) - return - - loaded_basket, loaded_sample = self.lidsample_to_basketsample( - loaded_lid, loaded_num - ) - - tool = self.tool_for_basket(loaded_basket) - - argin = [str(tool), "0", xshift, yshift, zshift] - - logging.getLogger("HWR").warning( - " ==========CATS=== unload sample, sending to cats: %s" % argin - ) - if loaded_ht == 1: - cmd_ret = self._execute_server_task(self._cmdUnloadHT, argin) - else: - cmd_ret = self._execute_server_task(self._cmdUnload, argin) - - def _do_abort(self): - """ - Aborts a running trajectory on the sample changer. - - :returns: None - :rtype: None - """ - if self.super_abort_cmd is not None: - self.super_abort_cmd() # stops super - self._cmdAbort() - self._update_state() # remove software flags like Loading.. reflects current hardware state - - def _check_coherence(self): - detected = self._chnSampleIsDetected.get_value() - loaded_lid = self._chnLidLoadedSample.get_value() - loaded_num = self._chnNumLoadedSample.get_value() - - if -1 in [loaded_lid, loaded_num] and detected: - return False, "Sample detected on Diffract. but there is no info about it" - - return True, "" - - def _get_shifts(self): - """ - Get the mounting position from the Diffractometer DS. - - @return: 3-tuple - """ - if self.shifts_channel is not None: - shifts = self.shifts_channel.get_value() - else: - shifts = None - return shifts - - # def path_running(self): - # """ - # Overides Cats90 method. - # - # @return: - # """ - # return (self._chnPathSafe.get_value() is not True) - - # TODO: fix return type - def is_ht_sample(self, address): - """ - Returns is sample address belongs to hot tool basket. - - @address: sample address - @return: int or boolean - """ - basket, sample = address.split(":") - try: - if int(basket) >= 100: - return int(sample) - else: - return False - except Exception: - return False - - def tool_for_basket(self, basketno): - """ - Returns the tool corresponding to the basket. - - @basketno: basket number - @return: int - """ - if basketno == 100: - return TOOL_SPINE - - return Cats90.tool_for_basket(self, basketno) - - def is_loaded_ht(self): - """ - 1 : has loaded ht - 0 : nothing loaded - -1 : loaded but not ht - """ - sample_lid = self._chnLidLoadedSample.get_value() - - if self.has_loaded_sample(): - if sample_lid == 100: - return 1 - else: - return -1 - else: - return 0 - - -def test_hwo(hwo): - hwo._update_cats_contents() - print(" Is path running? ", hwo.is_path_running()) - print(" Loading shifts: ", hwo._get_shifts()) - print(" Sample on diffr : ", hwo.cats_sample_on_diffr()) - print(" Baskets : ", hwo.basket_presence) - print(" Baskets : ", hwo.get_basket_list()) - if hwo.has_loaded_sample(): - print(" Loaded is: ", hwo.get_loaded_sample().get_coords()) - print(" Is mounted sample: ", hwo.is_mounted_sample((1, 1))) - - -if __name__ == "__main__": - test() diff --git a/mxcubecore/HardwareObjects/ALBA/ALBACatsMaint.py b/mxcubecore/HardwareObjects/ALBA/ALBACatsMaint.py deleted file mode 100644 index bcff58c5fc..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBACatsMaint.py +++ /dev/null @@ -1,64 +0,0 @@ -from mxcubecore.HardwareObjects.abstract.sample_changer.CatsMaint import ( - CatsMaint, -) - - -class ALBACatsMaint(CatsMaint): - def __init__(self, *args): - CatsMaint.__init__(self, *args) - - def init(self): - CatsMaint.init(self) - - # load ALBA attributes and commands from XML - self._chnAtHome = self.get_channel_object("_chnAtHome") - self.super_abort_cmd = self.get_command_object("super_abort") - - # channel to ask diffractometer for mounting position - self.shifts_channel = self.get_channel_object("shifts") - - def _do_abort(self): - if self.super_abort_cmd is not None: - self.super_abort_cmd() - self._cmdAbort() - - def _do_reset_memory(self): - """ - Reset CATS memory. - """ - # Check do_PRO6_RAH first - if self._chnAtHome.get_value() is True: - CatsMaint._do_reset_memory(self) - - def _do_reset(self): - """ - Reset CATS system. - """ - self._cmdAbort() - self._cmdReset() - self._do_reset_memory() - - def _do_operation_command(self, cmd, pars): - """ - Send a CATS command - - @cmd: command - @pars: command arguments - """ - CatsMaint._do_operation_command(self) - - def _get_shifts(self): - """ - Get the mounting position from the Diffractometer DS. - - @return: 3-tuple - """ - if self.shifts_channel is not None: - shifts = self.shifts_channel.get_value() - else: - shifts = None - return shifts - - -def test_hwo(hwo): - print(hwo._get_shifts()) diff --git a/mxcubecore/HardwareObjects/ALBA/ALBAClusterJob.py b/mxcubecore/HardwareObjects/ALBA/ALBAClusterJob.py deleted file mode 100644 index 644eb39522..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBAClusterJob.py +++ /dev/null @@ -1,117 +0,0 @@ -from XSDataMXCuBEv1_3 import XSDataResultMXCuBE -from xaloc import XalocJob -import os -import time -import logging - -import sys - -sys.path.append("/beamlines/bl13/controls/devel/pycharm/ALBAClusterClient") - - -root = os.environ["POST_PROCESSING_SCRIPTS_ROOT"] - - -class ALBAClusterJob(object): - def __init__(self, *args): - self.job = None - - def run(self, *args): - pass - - def wait_done(self, wait=True): - - if not self.job: - return - - time.sleep(0.5) - - state = self.job.state - - if not wait: - return state - - while state in ["RUNNING", "PENDING"]: - logging.getLogger("HWR").debug("Job / is %s" % state) - time.sleep(0.5) - state = self.job.state - - logging.getLogger("HWR").debug(' job finished with state: "%s"' % state) - return state - - def get_result(self, state): - pass - - -class ALBAAutoprocJob(ALBAClusterJob): - sls_script = os.path.join(root, "edna-mx/autoproc/edna-mx.autoproc.sl") - - def run(self, *args): - - jobname = os.path.basename(os.path.dirname(edna_directory)) - self.job = XalocJob( - "edna-autoproc", jobname, self.sls_script, input_file, edna_directory - ) - self.job.submit() - - -class ALBAEdnaProcJob(ALBAClusterJob): - sls_script = os.path.join(root, "edna-mx/ednaproc/edna-mx.ednaproc.sl") - - def run(self, *args): - collect_id, input_file, output_dir = args - self.job = XalocJob( - "edna-ednaproc", str(collect_id), self.sls_script, input_file, output_dir - ) - self.job.submit() - - -class ALBAStrategyJob(ALBAClusterJob): - - sls_script = os.path.join(root, "edna-mx/strategy/edna-mx.strategy.sl") - - def run(self, *args): - - logging.getLogger("HWR").debug("Starting StrategyJob - ") - - input_file, results_file, edna_directory = args - - jobname = os.path.basename(os.path.dirname(edna_directory)) - - self.job = XalocJob( - "edna-strategy", jobname, self.sls_script, input_file, edna_directory - ) - self.job.submit() - - logging.getLogger("HWR").debug(" StrategyJob - %s" % str(self.job)) - - self.edna_directory = os.path.dirname(input_file) - self.results_file = results_file - - logging.getLogger("HWR").debug(" input file: %s" % input_file) - logging.getLogger("HWR").debug(" edna directory: %s" % self.edna_directory) - - def get_result(self, state): - if state == "COMPLETED": - outfile = os.path.join( - self.edna_directory, "ControlInterfaceToMXCuBEv1_3_dataOutput.xml" - ) - - logging.getLogger("HWR").debug("Job / state is COMPLETED") - logging.getLogger("HWR").debug(" looking for file: %s" % outfile) - if os.path.exists(outfile): - job_output = open(outfile).read() - open(self.results_file, "w").write(job_output) - result = XSDataResultMXCuBE.parseFile(self.results_file) - else: - logging.getLogger("HWR").debug( - "EDNA Job finished without success / cannot find output file " - ) - result = "" - else: - logging.getLogger("HWR").debug( - "EDNA Job finished without success / state was %s" % (job.state) - ) - result = "" - - return result diff --git a/mxcubecore/HardwareObjects/ALBA/ALBACollect.py b/mxcubecore/HardwareObjects/ALBA/ALBACollect.py deleted file mode 100644 index 934f9136b4..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBACollect.py +++ /dev/null @@ -1,877 +0,0 @@ -# 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 . - -""" -ALBACollect -""" -import os -import time -import logging -import sys -import gevent -from mxcubecore.TaskUtils import task -from mxcubecore.HardwareObjects.abstract.AbstractCollect import AbstractCollect -from mxcubecore import HardwareRepository as HWR - - -__author__ = "Vicente Rey Bakaikoa" -__credits__ = ["MXCuBE collaboration"] -__version__ = "2.2." - - -class ALBACollect(AbstractCollect): - """Main data collection class. Inherited from AbstractMulticollect - Collection is done by setting collection parameters and - executing collect command - """ - - def __init__(self, name): - """ - - :param name: name of the object - :type name: string - """ - - AbstractCollect.__init__(self, name) - # HardwareObject.__init__(self, name) - - self._error_msg = "" - self.owner = None - self.osc_id = None - self._collecting = None - - self.helical_positions = None - self.saved_omega_velocity = None - - def init(self): - """ - Init method - """ - - self.ready_event = gevent.event.Event() - - self.supervisor_hwobj = self.get_object_by_role("supervisor") - - self.slowshut_hwobj = self.get_object_by_role("slow_shutter") - self.photonshut_hwobj = self.get_object_by_role("photon_shutter") - self.frontend_hwobj = self.get_object_by_role("frontend") - - self.ni_conf_cmd = self.get_command_object("ni_configure") - self.ni_unconf_cmd = self.get_command_object("ni_unconfigure") - - # some extra reading channels to be saved in image header - self.kappapos_chan = self.get_channel_object("kappapos") - self.phipos_chan = self.get_channel_object("phipos") - - undulators = [] - try: - for undulator in self["undulators"]: - undulators.append(undulator) - except Exception: - pass - - self.exp_type_dict = {"Mesh": "raster", "Helical": "Helical"} - - det_px, det_py = HWR.beamline.detector.get_pixel_size() - beam_div_hor, beam_div_ver = HWR.beamline.beam.get_beam_divergence() - - self.set_beamline_configuration( - synchrotron_name="ALBA", - directory_prefix=self.get_property("directory_prefix"), - default_exposure_time=HWR.beamline.detector.get_default_exposure_time(), - minimum_exposure_time=HWR.beamline.detector.get_minimum_exposure_time(), - detector_fileext=HWR.beamline.detector.get_file_suffix(), - detector_type=HWR.beamline.detector.get_detector_type(), - detector_manufacturer=HWR.beamline.detector.get_manufacturer(), - detector_model=HWR.beamline.detector.get_model(), - detector_px=det_px, - detector_py=det_py, - undulators=undulators, - focusing_optic=self.get_property("focusing_optic"), - monochromator_type=self.get_property("monochromator"), - beam_divergence_vertical=beam_div_ver, - beam_divergence_horizontal=beam_div_hor, - polarisation=self.get_property("polarisation"), - input_files_server=self.get_property("input_files_server"), - ) - - self.emit("collectConnected", (True,)) - self.emit("collectReady", (True,)) - - def data_collection_hook(self): - """Main collection hook - """ - - logging.getLogger("HWR").info("Running ALBA data collection hook") - - logging.getLogger("HWR").info(" -- wait for devices to finish moving --") - logging.getLogger("HWR").info(" + wait for resolution...") - HWR.beamline.resolution.wait_end_of_move() - logging.getLogger("HWR").info(" + wait for detector distance...") - HWR.beamline.detector.wait_move_distance_done() - logging.getLogger("HWR").info(" + wait for energy...") - HWR.beamline.energy.wait_move_energy_done() - - if self.aborted_by_user: - self.emit_collection_failed("Aborted by user") - self.aborted_by_user = False - return - - ### EDNA_REF, OSC, MESH, HELICAL - - exp_type = self.current_dc_parameters["experiment_type"] - logging.getLogger("HWR").debug("Running a collect (exp_type=%s)" % exp_type) - - if exp_type == "Characterization": - logging.getLogger("HWR").debug("Running a collect (CHARACTERIZATION)") - elif exp_type == "Helical": - logging.getLogger("HWR").debug("Running a helical collection") - logging.getLogger("HWR").debug( - " helical positions are: %s" % str(self.helical_positions) - ) - hpos = self.helical_positions - logging.getLogger("HWR").debug( - " phiy from %3.4f to %3.4f" % (hpos[0], hpos[4]) - ) - logging.getLogger("HWR").debug( - " phiz from %3.4f to %3.4f" % (hpos[1], hpos[5]) - ) - logging.getLogger("HWR").debug( - " sampx from %3.4f to %3.4f" % (hpos[2], hpos[6]) - ) - logging.getLogger("HWR").debug( - " sampy from %3.4f to %3.4f" % (hpos[3], hpos[7]) - ) - elif exp_type == "Mesh": - logging.getLogger("HWR").debug("Running a raster collection ()") - logging.getLogger("HWR").debug( - " number of lines are: %s" % self.mesh_num_lines - ) - logging.getLogger("HWR").debug( - " total nb of frames: %s" % self.mesh_total_nb_frames - ) - logging.getLogger("HWR").debug( - " mesh range : %s" % self.mesh_range - ) - logging.getLogger("HWR").debug( - " mesh center : %s" % self.mesh_center - ) - else: - logging.getLogger("HWR").debug("Running a collect (STANDARD)") - - osc_seq = self.current_dc_parameters["oscillation_sequence"][0] - - image_range = osc_seq["range"] - nb_images = osc_seq["number_of_images"] - total_range = image_range * nb_images - - ready = self.prepare_acquisition() - - if not ready: - self.collection_failed("Cannot prepare collection") - self.stop_collect() - return - - self._collecting = True - # for progressBar brick - self.emit("progressInit", "Collection", osc_seq["number_of_images"]) - - omega_pos = osc_seq["start"] - - logging.getLogger("HWR").info("Starting detector") - self.emit("collectStarted", (self.owner, 1)) - - first_image_no = osc_seq["start_image_number"] - - if exp_type == "OSC" or (exp_type == "Characterization" and nb_images == 1): - final_pos = self.prepare_collection( - start_angle=omega_pos, - nb_images=nb_images, - first_image_no=first_image_no, - ) - HWR.beamline.detector.start_collection() - self.collect_images(final_pos, nb_images, first_image_no) - elif exp_type == "Characterization" and nb_images > 1: # image one by one - for imgno in range(nb_images): - final_pos = self.prepare_collection( - start_angle=omega_pos, nb_images=1, first_image_no=first_image_no - ) - HWR.beamline.detector.start_collection() - self.collect_images(final_pos, 1, first_image_no) - first_image_no += 1 - omega_pos += 90 - - def collect_images(self, final_pos, nb_images, first_image_no): - # - # Run - # - logging.getLogger("HWR").info( - "collecting images, by moving omega to %s" % final_pos - ) - HWR.beamline.diffractometer.omega.set_value(final_pos) - self.wait_collection_done(nb_images, first_image_no) - self.data_collection_end() - self.collection_finished() - - def data_collection_end(self): - HWR.beamline.fast_shutter.cmdOut() - HWR.beamline.diffractometer.omega.set_velocity(60) - self.unconfigure_ni() - - def data_collection_failed(self): - logging.getLogger("HWR").info( - "Data collection failed. recovering sequence should go here" - ) - - def prepare_acquisition(self): - - fileinfo = self.current_dc_parameters["fileinfo"] - - basedir = fileinfo["directory"] - - # save omega velocity - self.saved_omega_velocity = HWR.beamline.diffractometer.omega.get_velocity() - - # create directories if needed - self.check_directory(basedir) - - # check fast shutter closed. others opened - shutok = self.check_shutters() - - if not shutok: - logging.getLogger("user_level_log").error( - " Shutters are not ready. BYPASSED. Comment line in ALBACollect.py" - ) - else: - logging.getLogger("user_level_log").error( - " Shutters ready but code is BYPASSED. Comment line in ALBACollect.py" - ) - - shutok = True # DELETE THIS AFTER TESTS - - if not shutok: - logging.getLogger("user_level_log").error(" Shutters not ready") - return False - - gevent.sleep(1) - logging.getLogger("HWR").info( - " Waiting for diffractometer to be ready. Now %s" - % str(HWR.beamline.diffractometer.current_state) - ) - HWR.beamline.diffractometer.wait_device_ready(timeout=10) - logging.getLogger("HWR").info(" diffractometer is now ready.") - - # go to collect phase - if not self.is_collect_phase(): - logging.getLogger("HWR").info( - " Not in collect phase. Asking supervisor to go" - ) - logging.getLogger("HWR").info( - " diffractometer is now ready. Now %s" - % str(HWR.beamline.diffractometer.current_state) - ) - success = self.go_to_collect() - if not success: - logging.getLogger("user_level_log").error( - "Cannot set COLLECT phase for diffractometer" - ) - return False - - detok = HWR.beamline.detector.prepare_acquisition(self.current_dc_parameters) - - return detok - - def prepare_collection(self, start_angle, nb_images, first_image_no): - # move omega to start angle - osc_seq = self.current_dc_parameters["oscillation_sequence"][0] - - # start_angle = osc_seq['start'] - # nb_images = osc_seq['number_of_images'] - - img_range = osc_seq["range"] - exp_time = osc_seq["exposure_time"] - - total_dist = nb_images * img_range - total_time = nb_images * exp_time - omega_speed = float(total_dist / total_time) - - logging.getLogger("HWR").info(" prepare detector was not ok.") - self.write_image_headers(start_angle) - - logging.getLogger("HWR").info( - " nb_images: %s / img_range: %s / exp_time: %s / total_distance: %s / speed: %s" - % (nb_images, img_range, exp_time, total_dist, omega_speed) - ) - logging.getLogger("HWR").info( - " setting omega velocity to 60 to go to intial position" - ) - HWR.beamline.diffractometer.omega.set_velocity(60) - - omega_acceltime = HWR.beamline.diffractometer.omega.get_acceleration() - - safe_delta = 9.0 * omega_speed * omega_acceltime - - init_pos = start_angle - safe_delta - final_pos = start_angle + total_dist + safe_delta - - logging.getLogger("HWR").info("Moving omega to initial position %s" % init_pos) - HWR.beamline.diffractometer.omega.set_value(init_pos) - - HWR.beamline.detector.prepare_collection(nb_images, first_image_no) - - HWR.beamline.diffractometer.omega.wait_end_of_move(timeout=10) - - logging.getLogger("HWR").info( - "Moving omega finished at %s" - % HWR.beamline.diffractometer.omega.get_value() - ) - - # program omega speed depending on exposure time - - logging.getLogger("HWR").info("Setting omega velocity to %s" % omega_speed) - HWR.beamline.diffractometer.omega.set_velocity(omega_speed) - if omega_speed != 0: - self.configure_ni(start_angle, total_dist) - - return final_pos - - def write_image_headers(self, start_angle): - fileinfo = self.current_dc_parameters["fileinfo"] - basedir = fileinfo["directory"] - - exp_type = self.current_dc_parameters["experiment_type"] - osc_seq = self.current_dc_parameters["oscillation_sequence"][0] - - nb_images = osc_seq["number_of_images"] - # start_angle = osc_seq['start'] - - img_range = osc_seq["range"] - - if exp_type == "Characterization": - angle_spacing = 90 - else: - angle_spacing = img_range - - exp_time = osc_seq["exposure_time"] - - # PROGRAM Image Headers - # latency_time = 0.003 - latency_time = HWR.beamline.detector.get_latency_time() - limaexpt = exp_time - latency_time - - self.image_headers = {} - - angle_info = [start_angle, img_range, angle_spacing] - - self.image_headers["nb_images"] = nb_images - self.image_headers["Exposure_time"] = "%.4f" % limaexpt - self.image_headers["Exposure_period"] = "%.4f" % exp_time - self.image_headers["Start_angle"] = "%f deg." % start_angle - self.image_headers["Angle_increment"] = "%f deg." % img_range - self.image_headers["Wavelength"] = HWR.beamline.energy.get_wavelength() - - self.image_headers["Detector_distance"] = "%.5f m" % ( - HWR.beamline.detector.distance.get_value() / 1000.0 - ) - self.image_headers["Detector_Voffset"] = "0 m" - - beamx, beamy = HWR.beamline.detector.get_beam_position() - self.image_headers["Beam_xy"] = "(%.2f, %.2f) pixels" % (beamx, beamy) - - self.image_headers["Filter_transmission"] = "%.4f" % ( - HWR.beamline.transmission.get_value() / 100.0 - ) - self.image_headers["Flux"] = "%.4g" % HWR.beamline.flux.get_value() - self.image_headers["Detector_2theta"] = "0.0000" - self.image_headers["Polarization"] = "0.99" - self.image_headers["Alpha"] = "0 deg." - - self.image_headers["Kappa"] = "%.4f deg." % self.kappapos_chan.get_value() - self.image_headers["Phi"] = "%.4f deg." % self.phipos_chan.get_value() - - self.image_headers["Chi"] = "0 deg." - self.image_headers["Oscillation_axis"] = "X, CW" - self.image_headers["N_oscillations"] = "1" - self.image_headers["Detector_2theta"] = "0.0000 deg" - - self.image_headers["Image_path"] = ": %s" % basedir - - self.image_headers["Threshold_setting"] = ( - "%0f eV" % HWR.beamline.detector.get_threshold() - ) - self.image_headers["Gain_setting"] = "%s" % str( - HWR.beamline.detector.get_threshold_gain() - ) - - self.image_headers["Tau"] = "%s s" % str(199.1e-09) - self.image_headers["Count_cutoff"] = "%s counts" % str(370913) - self.image_headers["N_excluded_pixels"] = "= %s" % str(1178) - self.image_headers["Excluded_pixels"] = ": %s" % str("badpix_mask.tif") - self.image_headers["Trim_file"] = ": %s" % str( - "p6m0108_E12661_T6330_vrf_m0p20.bin" - ) - - HWR.beamline.detector.set_image_headers(self.image_headers, angle_info) - - def wait_collection_done(self, nb_images, first_image_no): - - osc_seq = self.current_dc_parameters["oscillation_sequence"][0] - - # first_image_no = osc_seq['start_image_number'] - # nb_images = osc_seq['number_of_images'] - last_image_no = first_image_no + nb_images - 1 - - if nb_images > 1: - self.wait_save_image(first_image_no) - HWR.beamline.diffractometer.omega.wait_end_of_move(timeout=720) - self.wait_save_image(last_image_no) - - def wait_save_image(self, frame_number, timeout=25): - - fileinfo = self.current_dc_parameters["fileinfo"] - basedir = fileinfo["directory"] - template = fileinfo["template"] - - filename = template % frame_number - fullpath = os.path.join(basedir, filename) - - start_wait = time.time() - - logging.getLogger("HWR").debug(" waiting for image on disk: %s", fullpath) - - while not os.path.exists(fullpath): - dirlist = os.listdir(basedir) # forces directory flush ? - if (time.time() - start_wait) > timeout: - logging.getLogger("HWR").debug(" giving up waiting for image") - return False - time.sleep(0.2) - - self.last_saved_image = fullpath - - # generate thumbnails - archive_dir = fileinfo["archive_directory"] - self.check_directory(archive_dir) - - jpeg_filename = os.path.splitext(filename)[0] + ".jpeg" - thumb_filename = os.path.splitext(filename)[0] + ".thumb.jpeg" - - thumb_fullpath = os.path.join(archive_dir, thumb_filename) - jpeg_fullpath = os.path.join(archive_dir, jpeg_filename) - - logging.getLogger("HWR").debug( - " creating thumbnails for %s in: %s and %s" - % (fullpath, jpeg_fullpath, thumb_fullpath) - ) - cmd = "adxv_thumb 0.4 %s %s" % (fullpath, jpeg_fullpath) - os.system(cmd) - cmd = "adxv_thumb 0.1 %s %s" % (fullpath, thumb_fullpath) - os.system(cmd) - - logging.getLogger("HWR").debug(" writing thumbnails info in LIMS") - self._store_image_in_lims(frame_number) - - return True - - def check_shutters(self): - - # Check fast shutter - if HWR.beamline.fast_shutter.get_state() != 0: - return False - - # Check slow shutter - if self.slowshut_hwobj.get_state() != 1: - return False - - # Check photon shutter - if self.photonshut_hwobj.get_state() != 1: - return False - - # Check front end - if self.frontend_hwobj.get_state() != 1: - return False - - return True - - def get_image_headers(self): - headers = [] - return headers - - def collection_end(self): - # - # data collection end (or abort) - # - logging.getLogger("HWR").info(" finishing data collection ") - HWR.beamline.fast_shutter.cmdOut() - self.emit("progressStop") - - def check_directory(self, basedir): - if not os.path.exists(basedir): - try: - os.makedirs(basedir) - except OSError as e: - import errno - - if e.errno != errno.EEXIST: - raise - - def collect_finished(self, green): - logging.info("Data collection finished") - - def collect_failed(self, par): - logging.exception("Data collection failed") - self.current_dc_parameters["status"] = "failed" - exc_type, exc_value, exc_tb = sys.exc_info() - failed_msg = "Data collection failed!\n%s" % exc_value - self.emit( - "collectOscillationFailed", - ( - self.owner, - False, - failed_msg, - self.current_dc_parameters.get("collection_id"), - 1, - ), - ) - - HWR.beamline.detector.stop_collection() - HWR.beamline.diffractometer.omega.stop() - self.data_collection_end() - - def go_to_collect(self, timeout=180): - logging.getLogger("HWR").debug("sending supervisor to collect phase") - self.supervisor_hwobj.go_collect() - logging.getLogger("HWR").debug("supervisor sent to collect phase") - - gevent.sleep(0.5) - - t0 = time.time() - while True: - super_state = str(self.supervisor_hwobj.get_state()).upper() - cphase = self.supervisor_hwobj.get_current_phase().upper() - if super_state != "MOVING" and cphase == "COLLECT": - break - if time.time() - t0 > timeout: - logging.getLogger("HWR").debug( - "timeout sending supervisor to collect phase" - ) - break - gevent.sleep(0.5) - - logging.getLogger("HWR").debug( - "supervisor finished go collect phase task. phase is now: %s" % cphase - ) - - return self.is_collect_phase() - - def is_collect_phase(self): - return self.supervisor_hwobj.get_current_phase().upper() == "COLLECT" - - def go_to_sampleview(self, timeout=180): - logging.getLogger("HWR").debug("sending supervisor to sample view phase") - self.supervisor_hwobj.go_sample_view() - logging.getLogger("HWR").debug("supervisor sent to sample view phase") - - gevent.sleep(0.5) - - t0 = time.time() - while True: - super_state = str(self.supervisor_hwobj.get_state()).upper() - cphase = self.supervisor_hwobj.get_current_phase().upper() - if super_state != "MOVING" and cphase == "SAMPLE": - break - if time.time() - t0 > timeout: - logging.getLogger("HWR").debug( - "timeout sending supervisor to sample view phase" - ) - break - gevent.sleep(0.5) - - logging.getLogger("HWR").debug( - "supervisor finished go sample view phase task. phase is now: %s" % cphase - ) - - return self.is_sampleview_phase() - - def is_sampleview_phase(self): - return self.supervisor_hwobj.get_current_phase().upper() == "SAMPLE" - - def configure_ni(self, startang, total_dist): - logging.getLogger("HWR").debug( - "Configuring NI660 with pars 0, %s, %s, 0, 1" % (startang, total_dist) - ) - self.ni_conf_cmd(0.0, startang, total_dist, 0, 1) - - def unconfigure_ni(self): - self.ni_unconf_cmd() - - def open_safety_shutter(self): - """ implements prepare_shutters in collect macro """ - - # prepare ALL shutters - - # close fast shutter - if HWR.beamline.fast_shutter.get_state() != 0: - HWR.beamline.fast_shutter.close() - - # open slow shutter - if self.slowshut_hwobj.get_state() != 1: - self.slowshut_hwobj.open() - - # open photon shutter - if self.photonshut_hwobj.get_state() != 1: - self.photonshut_hwobj.open() - - # open front end - if self.frontend_hwobj.get_state() != 0: - self.frontend_hwobj.open() - - def open_detector_cover(self): - self.supervisor_hwobj.open_detector_cover() - - def open_fast_shutter(self): - # HWR.beamline.fast_shutter.open() - # this function is empty for ALBA. we are not opening the fast shutter. - # on the contrary open_safety_shutter (equivalent to prepare_shutters in original - # collect macro will first close the fast shutter and open the other three - pass - - def close_fast_shutter(self): - HWR.beamline.fast_shutter.cmdOut() - - def close_safety_shutter(self): - # we will not close safety shutter during collections - pass - - def close_detector_cover(self): - # we will not close detcover during collections - # self.supervisor.close_detector_cover() - pass - - def set_helical_pos(self, arg): - """ - Descript. : 8 floats describe - p1AlignmY, p1AlignmZ, p1CentrX, p1CentrY - p2AlignmY, p2AlignmZ, p2CentrX, p2CentrY - """ - self.helical_positions = [ - arg["1"]["phiy"], - arg["1"]["phiz"], - arg["1"]["sampx"], - arg["1"]["sampy"], - arg["2"]["phiy"], - arg["2"]["phiz"], - arg["2"]["sampx"], - arg["2"]["sampy"], - ] - - def setMeshScanParameters(self, num_lines, num_images_per_line, mesh_range): - """ - Descript. : - """ - pass - - @task - def _take_crystal_snapshot(self, filename): - """ - Descript. : - """ - if not self.is_sampleview_phase(): - self.go_to_sampleview() - - HWR.beamline.sample_view.save_snapshot(filename) - logging.getLogger("HWR").debug(" - snapshot saved to %s" % filename) - - @task - def move_motors(self, motor_position_dict): - """ - Descript. : - """ - HWR.beamline.diffractometer.move_motors(motor_position_dict) - - def create_file_directories(self): - """ - Method create directories for raw files and processing files. - Directorie for xds.input and auto_processing are created - """ - self.create_directories( - self.current_dc_parameters["fileinfo"]["directory"], - self.current_dc_parameters["fileinfo"]["process_directory"], - ) - - """create processing directories and img links""" - xds_directory, auto_directory, ednaproc_directory = self.prepare_input_files() - - try: - self.create_directories(xds_directory, auto_directory, ednaproc_directory) - os.system( - "chmod -R 777 %s %s %s" - % (xds_directory, auto_directory, ednaproc_directory) - ) - """todo, create link of imgs for auto_processing - try: - os.symlink(files_directory, os.path.join(process_directory, "img")) - except os.error, e: - if e.errno != errno.EEXIST: - raise - """ - # os.symlink(files_directory, os.path.join(process_directory, "img")) - except Exception: - logging.exception("Could not create processing file directory") - return - - if xds_directory: - self.current_dc_parameters["xds_dir"] = xds_directory - - if auto_directory: - self.current_dc_parameters["auto_dir"] = auto_directory - - # pass wavelength needed in auto processing input files - - osc_pars = self.current_dc_parameters["oscillation_sequence"][0] - osc_pars["wavelength"] = HWR.beamline.energy.get_wavelength() - - HWR.beamline.offline_processing.create_input_files( - xds_directory, auto_directory, self.current_dc_parameters - ) - - def prepare_input_files(self): - """ - Descript. : - """ - i = 1 - log = logging.getLogger("user_level_log") - - while True: - xds_input_file_dirname = "xds_%s_%s_%d" % ( - self.current_dc_parameters["fileinfo"]["prefix"], - self.current_dc_parameters["fileinfo"]["run_number"], - i, - ) - xds_directory = os.path.join( - self.current_dc_parameters["fileinfo"]["process_directory"], - xds_input_file_dirname, - ) - if not os.path.exists(xds_directory): - break - i += 1 - - self.current_dc_parameters["xds_dir"] = xds_directory - - mosflm_input_file_dirname = "mosflm_%s_%s_%d" % ( - self.current_dc_parameters["fileinfo"]["prefix"], - self.current_dc_parameters["fileinfo"]["run_number"], - i, - ) - mosflm_directory = os.path.join( - self.current_dc_parameters["fileinfo"]["process_directory"], - mosflm_input_file_dirname, - ) - - log.info(" - xds: %s / mosflm: %s" % (xds_directory, mosflm_directory)) - - while True: - ednaproc_dirname = "ednaproc_%s_%s_%d" % ( - self.current_dc_parameters["fileinfo"]["prefix"], - self.current_dc_parameters["fileinfo"]["run_number"], - i, - ) - ednaproc_directory = os.path.join( - self.current_dc_parameters["fileinfo"]["process_directory"], - ednaproc_dirname, - ) - if not os.path.exists(ednaproc_directory): - break - i += 1 - - self.current_dc_parameters["ednaproc_dir"] = ednaproc_directory - - return xds_directory, mosflm_directory, ednaproc_directory - - def get_undulators_gaps(self): - """ - Descript. : return triplet with gaps. In our case we have one gap, - others are 0 - """ - # TODO - try: - if self.chan_undulator_gap: - und_gaps = self.chan_undulator_gap.get_value() - if type(und_gaps) in (list, tuple): - return und_gaps - else: - return und_gaps - except Exception: - pass - return {} - - def get_slit_gaps(self): - """ - Descript. : - """ - if HWR.beamline.beam is not None: - return HWR.beamline.beam.get_slits_gap() - return None, None - - def get_beam_shape(self): - """ - Descript. : - """ - if HWR.beamline.beam is not None: - return HWR.beamline.beam.get_beam_shape() - - def get_machine_current(self): - """ - Descript. : - """ - if HWR.beamline.machine_info: - return HWR.beamline.machine_info.get_current() - else: - return 0 - - def get_machine_message(self): - """ - Descript. : - """ - if HWR.beamline.machine_info: - return HWR.beamline.machine_info.get_message() - else: - return "" - - def get_machine_fill_mode(self): - """ - Descript. : - """ - if HWR.beamline.machine_info: - return "FillMode not/impl" - # fill_mode = str(self.machine_info_hwobj.get_message()) - # return fill_mode[:20] - else: - return "" - - def trigger_auto_processing(self, event, frame): - if event == "after": - dc_pars = self.current_dc_parameters - HWR.beamline.offline_processing.trigger_auto_processing(dc_pars) - - -def test_hwo(hwo): - print("Shutters (ready for collect): ", hwo.check_shutters()) - print("Supervisor(collect phase): ", hwo.is_collect_phase()) - - print("Kappa ", hwo.kappapos_chan.get_value()) - print("Phi ", hwo.phipos_chan.get_value()) diff --git a/mxcubecore/HardwareObjects/ALBA/ALBADataAnalysis.py b/mxcubecore/HardwareObjects/ALBA/ALBADataAnalysis.py deleted file mode 100644 index 143c775033..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBADataAnalysis.py +++ /dev/null @@ -1,178 +0,0 @@ -from xaloc import XalocJob -from XSDataCommon import XSDataFile, XSDataString -from XSDataMXCuBEv1_3 import XSDataResultMXCuBE -from mxcubecore.HardwareObjects.EDNACharacterisation import EDNACharacterisation -from PyTango import DeviceProxy -import os -import time -import logging - -import sys - -sys.path.append("/beamlines/bl13/controls/devel/pycharm/ALBAClusterClient") - - -root = os.environ["POST_PROCESSING_SCRIPTS_ROOT"] - -sls_script = os.path.join(root, "edna-mx/strategy/edna-mx.strategy.sl") - - -class ALBADataAnalysis(EDNACharacterisation): - def init(self): - EDNACharacterisation.init(self) - - def prepare_input(self, edna_input): - - # used for strategy calculation (characterization) using data analysis cluster - # ALBA specific - - firstImage = None - - for dataSet in edna_input.getDataSet(): - for imageFile in dataSet.imageFile: - if imageFile.getPath() is None: - continue - firstImage = imageFile.path.value - break - - listImageName = os.path.basename(firstImage).split("_") - prefix = "_".join(listImageName[:-2]) - run_number = listImageName[-2] - i = 1 - - if hasattr(edna_input, "process_directory"): - edna_directory = os.path.join( - edna_input.process_directory, - "characterisation_%s_run%s_%d" % (prefix, run_number, i), - ) - while os.path.exists(edna_directory): - i += 1 - edna_directory = os.path.join( - edna_input.process_directory, - "characterisation_%s_run%s_%d" % (prefix, run_number, i), - ) - os.makedirs(edna_directory) - else: - raise RuntimeError("No process directory specified in edna_input") - - edna_input.process_directory = edna_directory - - output_dir = XSDataFile() - path = XSDataString() - path.set_value(edna_directory) - output_dir.setPath(path) - edna_input.setOutputFileDirectory(output_dir) - - def run_edna(self, input_file, results_file, edna_directory): - return self.run(input_file, results_file, edna_directory) - - def run(self, *args): - input_file, results_file, edna_directory = args - - jobname = os.path.basename(os.path.dirname(edna_directory)) - - logging.getLogger("HWR").debug(" XalocJob submiting ") - logging.getLogger("HWR").debug(" job_name: %s" % jobname) - logging.getLogger("HWR").debug(" sls_script: %s, " % sls_script) - logging.getLogger("HWR").debug(" input file: %s" % input_file) - logging.getLogger("HWR").debug(" results file: %s" % results_file) - logging.getLogger("HWR").debug(" edna directory: %s" % edna_directory) - - self.job = XalocJob( - "edna-strategy", jobname, sls_script, input_file, edna_directory - ) - self.job.submit() - - logging.getLogger("HWR").debug(" XalocJob submitted %s" % self.job.id) - - self.edna_directory = os.path.dirname(input_file) - self.input_file = os.path.basename(input_file) - # self.results_file = self.fix_path(results_file) - self.results_file = results_file - logging.getLogger("HWR").debug( - " self.results file: %s" % self.results_file - ) - - state = self.wait_done() - - if state == "COMPLETED": - logging.getLogger("HWR").debug("EDNA Job completed") - time.sleep(0.5) - result = self.get_result() - else: - logging.getLogger("HWR").debug( - "EDNA Job finished without success / state was %s" % (self.job.state) - ) - result = "" - - return result - - def fix_path(self, path): - outpath = path.replace("PROCESS_DATA", "PROCESS_DATA/RESULTS") - # dirname = os.path.dirname(path) - # basename = os.path.basename(path) - # outpath = os.path.join(dirname,'RESULTS',basename) - return outpath - - def wait_done(self): - - logging.getLogger("HWR").debug("Polling for Job state") - time.sleep(0.5) - logging.getLogger("HWR").debug("Polling for Job state 2") - - try: - state = self.job.state - logging.getLogger("HWR").debug("Job / is %s" % str(state)) - except Exception: - import traceback - - logging.getLogger("HWR").debug( - "Polling for Job state 3. exception happened" - ) - logging.getLogger("HWR").debug(" %s " % traceback.format_exc()) - - while state in ["RUNNING", "PENDING"]: - logging.getLogger("HWR").debug("Job / is %s" % state) - time.sleep(0.5) - state = self.job.state - - logging.getLogger("HWR").debug("Returning") - logging.getLogger("HWR").debug("Returning %s" % str(state)) - return state - - def get_result(self): - - jobstatus = self.job.status - - # outname = self.input_file.replace("Input", "Output") - # outfile = os.path.join( self.edna_directory, outname) - - logging.getLogger("HWR").debug("Job / state is COMPLETED") - logging.getLogger("HWR").debug(" job status dump: %s" % jobstatus) - logging.getLogger("HWR").debug(" looking for file: %s" % self.results_file) - - if os.path.exists(self.results_file): - # job_output = open(outfile).read() - # logging.getLogger("HWR").debug(" EDNA results file found. loading it") - # open(self.results_file, "w").write(job_output) - logging.getLogger("HWR").debug(" EDNA results file found 2") - result = XSDataResultMXCuBE.parseFile(self.results_file) - logging.getLogger("HWR").debug(" EDNA results file found 3") - logging.getLogger("HWR").debug( - "EDNA Result loaded from file / result is=%s" % str(type(result)) - ) - else: - logging.getLogger("HWR").debug( - "EDNA Job finished without success / cannot find output file " - ) - result = "" - - return result - - -def test_hwo(hwo): - ofile = "/tmp/edna/edna_result" - odir = "/tmp/edna" - test_input_file = "/beamlines/bl13/projects/cycle2018-I/2018012551-bcalisto/mx2018012551/DATA/20180131/PROCESS_DATA/characterisation_ref-Thrombin-TB-TTI1_A_run1_1/EDNAInput_2004391.xml" - result = hwo.run_edna(test_input_file, ofile, odir) - print(result) diff --git a/mxcubecore/HardwareObjects/ALBA/ALBAEnergy.py b/mxcubecore/HardwareObjects/ALBA/ALBAEnergy.py deleted file mode 100644 index 8109f99414..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBAEnergy.py +++ /dev/null @@ -1,74 +0,0 @@ -import logging - -from mxcubecore.BaseHardwareObjects import Device -from mxcubecore import HardwareRepository as HWR - - -class ALBAEnergy(Device): - def __init__(self, *args): - Device.__init__(self, *args) - self.energy_position = None - self.wavelength_position = None - - def init(self): - self.wavelength_hwobj = self.get_object_by_role("wavelength") - - HWR.beamline.energy.connect("valueChanged", self.energy_position_changed) - self.wavelength_hwobj.connect("valueChanged", self.wavelength_position_changed) - - def is_ready(self): - return True - - def get_value(self): - if self.energy_position is None: - self.energy_position = HWR.beamline.energy.get_value() - return self.energy_position - - def get_wavelength(self): - if self.wavelength_position is None: - self.wavelength_position = self.wavelength_hwobj.get_value() - return self.wavelength_position - - def re_emit_values(self): - HWR.beamline.energy.re_emit_values() - - def energy_position_changed(self, value): - self.energy_position = value - if None not in [self.energy_position, self.wavelength_position]: - self.emit("energyChanged", self.energy_position, self.wavelength_position) - - def wavelength_position_changed(self, value): - self.wavelength_position = value - if None not in [self.energy_position, self.wavelength_position]: - self.emit("energyChanged", self.energy_position, self.wavelength_position) - - def set_value(self, value): - current_egy = self.get_value() - - logging.getLogger("HWR").debug( - "moving energy to %s. now is %s" % (value, current_egy) - ) - HWR.beamline.energy.set_value(value) - - def wait_move_energy_done(self): - HWR.beamline.energy.wait_end_of_move() - - def set_wavelength(self, value): - self.wavelength_hwobj.set_value(value) - - def get_limits(self): - return HWR.beamline.energy.get_limits() - - def get_wavelength_limits(self): - return self.wavelength_hwobj.get_limits() - - -def test_hwo(hwo): - - print("Wavelength is: ", hwo.get_wavelength()) - print("Energy limits are: ", hwo.get_limits()) - print("Wavelength limits are: ", hwo.get_wavelength_limits()) - - -if __name__ == "__main__": - test() diff --git a/mxcubecore/HardwareObjects/ALBA/ALBAEpsActuator.py b/mxcubecore/HardwareObjects/ALBA/ALBAEpsActuator.py deleted file mode 100644 index 7edbb9b583..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBAEpsActuator.py +++ /dev/null @@ -1,156 +0,0 @@ -"""Tango Shutter Hardware Object -Example XML:: - - - Photon Shutter - bl13/ct/eps-plc-01 - pshu - Open,Closed - - - -Public Interface: - Commands: - int get_state() - Description: - returns current state - Output: - integer value describing the state - current states correspond to: - 0: out - 1: in - 9: moving - 11: alarm - 13: unknown - 23: fault - - string getStatus() - Description: - returns current state as a string that can contain a more - descriptive information about current state - - Output: - status string - - cmdIn() - Executes the command associated to the "In" action - cmdOut() - Executes the command associated to the "Out" action - - Signals: - stateChanged - -""" - -from mxcubecore import HardwareRepository as HWR -from mxcubecore import BaseHardwareObjects -import logging - -STATE_OUT, STATE_IN, STATE_MOVING, STATE_FAULT, STATE_ALARM, STATE_UNKNOWN = ( - 0, - 1, - 9, - 11, - 13, - 23, -) - - -class ALBAEpsActuator(BaseHardwareObjects.Device): - - states = { - STATE_OUT: "out", - STATE_IN: "in", - STATE_MOVING: "moving", - STATE_FAULT: "fault", - STATE_ALARM: "alarm", - STATE_UNKNOWN: "unknown", - } - - default_state_strings = ["Out", "In"] - - def __init__(self, name): - BaseHardwareObjects.Device.__init__(self, name) - - def init(self): - self.actuator_state = STATE_UNKNOWN - - try: - self.actuator_channel = self.get_channel_object("actuator") - self.actuator_channel.connect_signal("update", self.stateChanged) - except KeyError: - logging.getLogger().warning( - "%s: cannot report EPS Actuator State", self.name() - ) - - try: - state_string = self.get_property("states") - if state_string is None: - self.state_strings = self.default_state_strings - else: - states = state_string.split(",") - self.state_strings = states[1].strip(), states[0].strip() - except Exception: - import traceback - - logging.getLogger("HWR").warning(traceback.format_exc()) - self.state_strings = self.default_state_strings - - def get_state(self): - state = self.actuator_channel.get_value() - self.actuator_state = self.convert_state(state) - return self.actuator_state - - def convert_state(self, state): - if state == 0: - act_state = STATE_OUT - elif state == 1: - act_state = STATE_IN - else: - act_state = STATE_UNKNOWN - return act_state - - def stateChanged(self, value): - # - # emit signal - # - self.actuator_state = self.convert_state(value) - self.emit("stateChanged", ((self.actuator_state),)) - - def getUserName(self): - return self.username - - def getStatus(self): - """ - """ - state = self.get_state() - - if state in [STATE_OUT, STATE_IN]: - return self.state_strings[state] - elif state in self.states: - return self.states[state] - else: - return "Unknown" - - def open(self): - self.cmdIn() - - def close(self): - self.cmdOut() - - def cmdIn(self): - self.actuator_channel.set_value(1) - - def cmdOut(self): - self.actuator_channel.set_value(0) - - -def test_hwo(hwo): - print("Name is: ", hwo.getUserName()) - print("Shutter state is: ", hwo.get_state()) - print("Shutter status is: ", hwo.getStatus()) - - # print "Opening it" - # print hwo.open() - # print "Closing it" - # print hwo.close() diff --git a/mxcubecore/HardwareObjects/ALBA/ALBAFastShutter.py b/mxcubecore/HardwareObjects/ALBA/ALBAFastShutter.py deleted file mode 100644 index 3848a6aeb0..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBAFastShutter.py +++ /dev/null @@ -1,227 +0,0 @@ -"""Tango Shutter Hardware Object -Example XML:: - - - Photon Shutter - bl13/ct/eps-plc-01 - pshu - Open,Closed - - - -Public Interface: - Commands: - int get_state() - Description: - returns current state - Output: - integer value describing the state - current states correspond to: - 0: out - 1: in - 9: moving - 11: alarm - 13: unknown - 23: fault - - string getStatus() - Description: - returns current state as a string that can contain a more - descriptive information about current state - - Output: - status string - - cmdIn() - Executes the command associated to the "In" action - cmdOut() - Executes the command associated to the "Out" action - - Signals: - stateChanged - -""" - -from mxcubecore import HardwareRepository as HWR -from mxcubecore import BaseHardwareObjects -import logging -import time - -STATE_OUT, STATE_IN, STATE_MOVING, STATE_FAULT, STATE_ALARM, STATE_UNKNOWN = ( - 0, - 1, - 9, - 11, - 13, - 23, -) - - -class ALBAFastShutter(BaseHardwareObjects.Device): - - states = { - STATE_OUT: "out", - STATE_IN: "in", - STATE_MOVING: "moving", - STATE_FAULT: "fault", - STATE_ALARM: "alarm", - STATE_UNKNOWN: "unknown", - } - - default_state_strings = ["Out", "In"] - - def __init__(self, name): - BaseHardwareObjects.Device.__init__(self, name) - - def init(self): - - self.actuator_state = STATE_UNKNOWN - self.actuator_value = None - self.motor_position = None - self.motor_state = None - - try: - self.nistart_cmd = self.get_command_object("nistart") - self.nistop_cmd = self.get_command_object("nistop") - - self.actuator_channel = self.get_channel_object("actuator") - self.motorpos_channel = self.get_channel_object("motorposition") - self.motorstate_channel = self.get_channel_object("motorstate") - - self.actuator_channel.connect_signal("update", self.stateChanged) - self.motorpos_channel.connect_signal("update", self.motor_positions_changed) - self.motorstate_channel.connect_signal("update", self.motorStateChanged) - except KeyError: - logging.getLogger().warning("%s: cannot report FrontEnd State", self.name()) - - try: - state_string = self.get_property("states") - if state_string is None: - self.state_strings = self.default_state_strings - else: - states = state_string.split(",") - self.state_strings = states[1].strip(), states[0].strip() - except Exception: - import traceback - - logging.getLogger("HWR").warning(traceback.format_exc()) - self.state_strings = self.default_state_strings - - def get_state(self): - if self.actuator_state == STATE_UNKNOWN: - self.actuator_value = self.actuator_channel.get_value() - self.motor_position = self.motorpos_channel.get_value() - self.motor_state = self.motorstate_channel.get_value() - self.update_state() - return self.actuator_state - - def update_state(self): - - if None in [self.actuator_value, self.motor_position, self.motor_state]: - act_state = STATE_UNKNOWN - elif str(self.motor_state) == "MOVING": - act_state = STATE_MOVING - elif str(self.motor_state) != "ON" or abs(self.motor_position) > 0.01: - act_state = STATE_ALARM - else: - state = self.actuator_value.lower() - - if state == "high": - act_state = STATE_OUT - else: - act_state = STATE_IN - - if act_state != self.actuator_state: - self.actuator_state = act_state - self.emitStateChanged() - - def stateChanged(self, value): - self.actuator_value = value - self.update_state() - - def motor_positions_changed(self, value): - self.motor_position = value - self.update_state() - - def motorStateChanged(self, value): - self.motor_state = value - self.update_state() - - def emitStateChanged(self): - # - # emit signal - # - self.emit("fastStateChanged", ((self.actuator_state),)) - - def getMotorPosition(self): - if self.motor_position is None: - self.motor_position = self.motorpos_channel.get_value() - return self.motor_position - - def getMotorState(self): - if self.motor_state is None: - self.motor_state = self.motorstate_channel.get_value() - return self.motor_state - - def getUserName(self): - return self.username - - def getStatus(self): - """ - """ - state = self.get_state() - - if state in [STATE_OUT, STATE_IN]: - return self.state_strings[state] - elif state in self.states: - return self.states[state] - else: - return "Unknown" - - def cmdIn(self): - self.open() - - def cmdOut(self): - self.close() - - def close(self): - self.motorpos_channel.set_value(0) - self.set_ttl("High") - - def open(self): - self.motorpos_channel.set_value(0) - self.set_ttl("Low") - - def set_ttl(self, value): - self.nistop_cmd() - self.actuator_channel.set_value(value) - self.nistart_cmd() - - def is_open(self): - if self.actuator_state == STATE_IN: - return True - else: - return False - - def is_close(self): - if self.actuator_state == STATE_OUT: - return True - else: - return False - - -def test_hwo(hwo): - print("Name is: ", hwo.getUserName()) - - print("Shutter state is: ", hwo.get_state()) - print("Shutter status is: ", hwo.getStatus()) - print("Motor position is: ", hwo.getMotorPosition()) - print("Motor state is: ", hwo.getMotorState()) - # hwo.open() - # time.sleep(2) - # print "is_open?" , hwo.is_open() - # print "is_close?" , hwo.is_close() - - -if __name__ == "__main__": - test() diff --git a/mxcubecore/HardwareObjects/ALBA/ALBAFlux.py b/mxcubecore/HardwareObjects/ALBA/ALBAFlux.py deleted file mode 100644 index 2e3dca2b78..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBAFlux.py +++ /dev/null @@ -1,43 +0,0 @@ -from mxcubecore.HardwareObjects.abstract import AbstractFlux -from mxcubecore.BaseHardwareObjects import Device -import taurus -import logging - - -class ALBAFlux(Device, AbstractFlux.AbstractFlux): - def init(self): - super(ALBAFlux, self).init() - self.current_dev = taurus.Device("pc/mach_attrpc_ctrl/1") - self.vars_dev = taurus.Device("bl13/ct/variables") - self.trans_mot = taurus.Device("mbattrans") - - def get_value(self): - fluxlast = self.vars_dev["fluxlast"].value - - try: - if fluxlast > 1e7: - return self.last_current_trans() - except Exception: - pass - - logging.getLogger("HWR").debug( - " Abnormally low value of flux. Returning default value" - ) - default_flux = 6e11 * self.get_transmission() - return default_flux - - def get_transmission(self): - """ returns transmission between 0 and 1""" - return self.trans_mot.position / 100.0 - - def last_current_trans(self): - current = self.current_dev.value - fluxlastnorm = self.vars_dev["fluxlastnorm"].value - - last_current = (fluxlastnorm / 250.0) * current - - return last_current * self.get_transmission() - - -def test_hwo(hwo): - print(hwo.get_value()) diff --git a/mxcubecore/HardwareObjects/ALBA/ALBAFrontEnd.py b/mxcubecore/HardwareObjects/ALBA/ALBAFrontEnd.py deleted file mode 100644 index ce507fb146..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBAFrontEnd.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -The ALBAFastShutter hardware object is a variation of the ALBAEpsActuator -where the command to open/close is done on a different channel than the -reading of the shutter state. - -The interface is otherwise exactly the same as the ALBAEpsActuator - -Example XML:: - - - Front Shutter - bl13/ct/eps-plc-01 - fe_open - OPEN_FE - CLOSE_FE - Open,Closed - - -""" - -from mxcubecore import HardwareRepository as HWR -from mxcubecore import BaseHardwareObjects -import logging - -from ALBAEpsActuator import ALBAEpsActuator - - -class ALBAFrontEnd(ALBAEpsActuator): - def init(self): - ALBAEpsActuator.init(self) - - self.open_channel = self.get_channel_object("open_command") - self.close_channel = self.get_channel_object("close_command") - - def cmdIn(self): - self.open_channel.set_value(True) - # self.actuator_channel.set_value(1) - - def cmdOut(self): - self.close_channel.set_value(True) - # self.actuator_channel.set_value(0) - - -def test_hwo(hwo): - print("Name is: ", hwo.getUserName()) - print("Shutter state is: ", hwo.get_state()) - print("Shutter status is: ", hwo.getStatus()) - - # print "Opening it" - # print hwo.open() - # print "Closing it" - # print hwo.close() diff --git a/mxcubecore/HardwareObjects/ALBA/ALBAFrontLight.py b/mxcubecore/HardwareObjects/ALBA/ALBAFrontLight.py deleted file mode 100644 index 1c9024dc89..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBAFrontLight.py +++ /dev/null @@ -1,132 +0,0 @@ -from mxcubecore import HardwareRepository as HWR -from mxcubecore.BaseHardwareObjects import Device -import logging - - -class ALBAFrontLight(Device): - def __init__(self, *args): - Device.__init__(self, *args) - self.limits = [None, None] - - self.state = None - self.register_state = None - - self.current_level = None - self.memorized_level = None - self.previous_level = None - - self.default_off_threshold = 0.01 - self.off_threshold = None - - def init(self): - - self.level_channel = self.get_channel_object("light_level") - self.state_channel = self.get_channel_object("state") - threshold = self.get_property("off_threshold") - - if threshold is not None: - try: - self.off_threshold = float(threshold) - except Exception: - self.off_threshold = self.default_threshold - logging.getLogger("HWR").info( - "OFF Threshold for front light is not valid. Using %s" - % self.off_threshold - ) - - limits = self.get_property("limits") - if limits is not None: - lims = limits.split(",") - if len(lims) == 2: - self.limits = map(float, lims) - - self.level_channel.connect_signal("update", self.level_changed) - self.state_channel.connect_signal("update", self.register_state_changed) - - def is_ready(self): - return True - - def level_changed(self, value): - self.current_level = value - self.update_current_state() - - self.emit("levelChanged", self.current_level) - - def register_state_changed(self, value): - self.register_state = str(value).lower() - self.update_current_state() - - def update_current_state(self): - if self.register_state == "on": - if ( - self.off_threshold is not None - and self.current_level < 0.9 * self.off_threshold - ): - newstate = "off" - else: - newstate = "on" - elif self.register_state == "off": - newstate = "off" - else: - newstate = "fault" - - if newstate != self.state: - if newstate == "off": - self.memorized_level = self.previous_level - - self.state = newstate - self.emit("stateChanged", self.state) - - self.previous_level = self.current_level - - def get_limits(self): - return self.limits - - def get_state(self): - self.register_state = str(self.state_channel.get_value()).lower() - self.update_current_state() - return self.state - - def getUserName(self): - return self.username - - def getLevel(self): - self.current_level = self.level_channel.get_value() - return self.current_level - - def setLevel(self, level): - logging.getLogger("HWR").debug( - "Setting level in %s to %s" % (self.username, level) - ) - self.level_channel.set_value(float(level)) - - def setOn(self): - logging.getLogger("HWR").debug("Setting front light on") - if self.memorized_level is not None: - if self.memorized_level < self.off_threshold: - value = self.off_threshold - else: - value = self.memorized_level - logging.getLogger("HWR").debug(" setting value to") - self.level_channel.set_value(value) - else: - self.level_channel.set_value(self.off_threshold) - - def setOff(self): - logging.getLogger("HWR").debug("Setting front light off") - self.level_channel.set_value(0.0) - - -def test(): - hwr = HWR.get_hardware_repository() - hwr.connect() - - light = hwr.get_hardware_object("/frontlight") - print('\nLight control for "%s"\n' % light.getUserName()) - print(" Level limits are:", light.get_limits()) - print(" Current level is:", light.getLevel()) - print(" Current state is:", light.get_state()) - - -if __name__ == "__main__": - test() diff --git a/mxcubecore/HardwareObjects/ALBA/ALBAISPyBClient.py b/mxcubecore/HardwareObjects/ALBA/ALBAISPyBClient.py deleted file mode 100644 index a9259d0df6..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBAISPyBClient.py +++ /dev/null @@ -1,87 +0,0 @@ -import logging -from mxcubecore import HardwareRepository as HWR - -from ISPyBClient import ISPyBClient - - -class ALBAISPyBClient(ISPyBClient): - def ldap_login(self, login_name, psd, ldap_connection): - # overwrites standard ldap login is ISPyBClient.py - # to query for homeDirectory - - if ldap_connection is None: - ldap_connection = self.ldapConnection - - ok, msg = ldap_connection.login( - login_name, psd, fields=["uid", "homeDirectory"] - ) - - if ok: - vals = ldap_connection.get_field_values() - if "homeDirectory" in vals: - home_dir = vals["homeDirectory"][0] - logging.getLogger("HWR").debug( - " homeDirectory for user %s is %s" % (login_name, home_dir) - ) - # HWR.beamline.session.set_base_data_directories(home_dir, home_dir, home_dir) - HWR.beamline.session.set_ldap_homedir(home_dir) - else: - home_dir = "/tmp" - HWR.beamline.session.set_ldap_homedir(home_dir) - - return ok, msg - - def translate(self, code, what): - """ - Given a proposal code, returns the correct code to use in the GUI, - or what to send to LDAP, user office database, or the ISPyB database. - """ - logging.getLogger("HWR").debug("translating %s %s" % (code, what)) - if what == "ldap": - if code == "mx": - return "u" - - if what == "ispyb": - if code == "u": - return "mx" - - return code - - def prepare_collect_for_lims(self, mx_collect_dict): - # Attention! directory passed by reference. modified in place - - for i in range(4): - try: - prop = "xtalSnapshotFullPath%d" % (i + 1) - path = mx_collect_dict[prop] - ispyb_path = HWR.beamline.session.path_to_ispyb(path) - logging.debug("ALBA ISPyBClient - %s is %s " % (prop, ispyb_path)) - mx_collect_dict[prop] = ispyb_path - except Exception: - pass - - def prepare_image_for_lims(self, image_dict): - for prop in ["jpegThumbnailFileFullPath", "jpegFileFullPath"]: - try: - path = image_dict[prop] - ispyb_path = HWR.beamline.session.path_to_ispyb(path) - image_dict[prop] = ispyb_path - except Exception: - pass - - -def test_hwo(hwo): - proposal = "mx2018012551" - proposal = "mx2018002222" - pasw = "2222008102" - - info = hwo.login(proposal, pasw) - # info = hwo.get_proposal(proposal_code, proposal_number) - # info = hwo.get_proposal_by_username("u2020000007") - print(info["status"]) - - print("Getting associated samples") - session_id = 58248 - proposal_id = 8250 - samples = hwo.get_samples(proposal_id, session_id) - print(samples) diff --git a/mxcubecore/HardwareObjects/ALBA/ALBAMachineInfo.py b/mxcubecore/HardwareObjects/ALBA/ALBAMachineInfo.py deleted file mode 100644 index 6b480dca64..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBAMachineInfo.py +++ /dev/null @@ -1,208 +0,0 @@ -# -# 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 . - -""" -[Name] -ALBAMachineInfo - -[Description] -Hardware Object is used to get relevant machine information -(machine current, time to next injection, status, etc) -Based on EMBL HwObj - -[Channels] -- MachineCurrent -- TopUpRemaining -- State - -[Commands] - -[Emited signals] -- valuesChanged - -[Functions] -- None - -[Included Hardware Objects] -- None - - -Example Hardware Object XML file : -================================== - - Mach - mach/ct/gateway - State - Current - TopUpRemaining - -""" - -import logging -import time -from gevent import spawn -from urllib2 import urlopen -from datetime import datetime, timedelta -from mxcubecore import HardwareRepository as HWR -from mxcubecore.BaseHardwareObjects import Equipment - - -__author__ = "Jordi Andreu" -__credits__ = ["MXCuBE collaboration"] - -__version__ = "2.2." -__maintainer__ = "Jordi Andreu" -__email__ = "jandreu[at]cells.es" -__status__ = "Draft" - - -class ALBAMachineInfo(Equipment): - """ - Descript. : Displays actual information about the machine status. - """ - - def __init__(self, name): - Equipment.__init__(self, name) - self.logger = logging.getLogger("HWR MachineInfo") - self.logger.info("__init__()") - - """ - Descript. : - """ - # Parameters values - self.values_dict = {} - self.values_dict["mach_current"] = None - self.values_dict["mach_status"] = "" - self.values_dict["topup_remaining"] = "" - # Dictionary for booleans indicating if values are in range - # self.values_in_range_dict = {} - self.chan_mach_current = None - self.chan_mach_status = None - self.chan_topup_remaining = None - - def init(self): - """ - Descript. : Inits channels from xml configuration. - """ - try: - self.chan_mach_current = self.get_channel_object("MachCurrent") - if self.chan_mach_current is not None: - self.chan_mach_current.connect_signal( - "update", self.mach_current_changed - ) - - self.chan_mach_status = self.get_channel_object("MachStatus") - if self.chan_mach_status is not None: - self.chan_mach_status.connect_signal("update", self.mach_status_changed) - - self.chan_topup_remaining = self.get_channel_object("TopUpRemaining") - if self.chan_topup_remaining is not None: - self.chan_topup_remaining.connect_signal( - "update", self.topup_remaining_changed - ) - except KeyError: - self.logger.warning("%s: cannot read machine info", self.name()) - - def mach_current_changed(self, value): - """ - Descript. : Function called if the machine current is changed - Arguments : new machine current (float) - Return : - - """ - if ( - self.values_dict["mach_current"] is None - or abs(self.values_dict["mach_current"] - value) > 0.10 - ): - self.values_dict["mach_current"] = value - self.re_emit_values() - self.logger.debug("New machine current value=%smA" % value) - - def mach_status_changed(self, status): - """ - Descript. : Function called if machine status is changed - Arguments : new machine status (string) - Return : - - """ - self.values_dict["mach_status"] = str(status) - self.re_emit_values() - self.logger.debug("New machine status=%s" % status) - - def topup_remaining_changed(self, value): - """ - Descript. : Function called if topup ramaining is changed - Arguments : new topup remainin (float) - Return : - - """ - self.values_dict["topup_remaining"] = value - self.re_emit_values() - self.logger.debug("New top-up remaining time=%ss" % value) - - def re_emit_values(self): - """ - Descript. : Updates storage disc information, detects if intensity - and storage space is in limits, forms a value list - and value in range list, both emited by qt as lists - Arguments : - - Return : - - """ - - values_to_send = [] - values_to_send.append(self.values_dict["mach_current"]) - values_to_send.append(self.values_dict["mach_status"]) - values_to_send.append(self.values_dict["topup_remaining"]) - - self.emit("valuesChanged", values_to_send) - self.logger.debug("SIGNAL valuesChanged emitted") - - def get_mach_current(self): - try: - value = self.chan_mach_current.get_value() - except Exception as e: - self.logger.error("Cannot read machine current value, returning 0") - value = 0 - finally: - return value - # return self.values_dict['mach_current'] - - def get_current(self): - return self.get_mach_current() - - def get_message(self): - return "Machinfo status: %s" % self.get_mach_status() - - # def get_current_value(self): - # """ - # Descript. : - # """ - # return self.values_dict['current'] - - def get_mach_status(self): - return self.chan_mach_status.get_value() - - # return self.values_dict['mach_status'] - - def get_topup_remaining(self): - return self.chan_topup_remaining.get_value() - - -# return self.values_dict['remaining'] - - -def test_hwo(hwo): - print("Current is", hwo.get_current()) diff --git a/mxcubecore/HardwareObjects/ALBA/ALBAMiniDiff.py b/mxcubecore/HardwareObjects/ALBA/ALBAMiniDiff.py deleted file mode 100644 index a69e7bf193..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBAMiniDiff.py +++ /dev/null @@ -1,565 +0,0 @@ -# -# 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 . - -""" -[Name] -ALBAMiniDiff - -[Description] -Specific HwObj for M2D2 diffractometer @ ALBA - -[Channels] -- N/A - -[Commands] -- N/A - -[Emited signals] -- pixelsPerMmChanged -- phiMotorMoved -- stateChanged -- zoomMotorPredefinedPositionChanged - - -[Functions] -- None - -[Included Hardware Objects] -- None -""" - -import logging -import time -from mxcubecore.HardwareObjects.GenericDiffractometer import ( - GenericDiffractometer, - DiffractometerState, -) -import gevent - -from mxcubecore.HardwareObjects import queue_model_objects - - -__author__ = "Jordi Andreu" -__credits__ = ["MXCuBE collaboration"] - -__version__ = "2.2." -__maintainer__ = "Jordi Andreu" -__email__ = "jandreu[at]cells.es" -__status__ = "Draft" - - -class ALBAMiniDiff(GenericDiffractometer): - """ - Specific diffractometer HwObj for XALOC beamline. - """ - - def __init__(self, *args): - GenericDiffractometer.__init__(self, *args) - self.centring_hwobj = None - self.super_hwobj = None - - def init(self): - - self.calibration = self.get_object_by_role("calibration") - - self.centring_hwobj = self.get_object_by_role("centring") - self.super_hwobj = self.get_object_by_role("beamline-supervisor") - - if self.centring_hwobj is None: - logging.getLogger("HWR").debug("ALBAMinidiff: Centring math is not defined") - - if self.super_hwobj is not None: - self.connect( - self.super_hwobj, "stateChanged", self.supervisor_state_changed - ) - self.connect( - self.super_hwobj, "phaseChanged", self.supervisor_phase_changed - ) - - self.state_channel = self.get_channel_object("State") - self.connect(self.state_channel, "update", self.state_changed) - # This is not used - self.cmd_start_auto_focus = self.get_command_object("startAutoFocus") - - self.phi_motor_hwobj = self.get_object_by_role("phi") - self.phiz_motor_hwobj = self.get_object_by_role("phiz") - self.phiy_motor_hwobj = self.get_object_by_role("phiy") - self.zoom_motor_hwobj = self.get_object_by_role("zoom") - self.focus_motor_hwobj = self.get_object_by_role("focus") - self.sample_x_motor_hwobj = self.get_object_by_role("sampx") - self.sample_y_motor_hwobj = self.get_object_by_role("sampy") - - if self.phi_motor_hwobj is not None: - self.connect( - self.phi_motor_hwobj, "stateChanged", self.phi_motor_state_changed - ) - self.connect(self.phi_motor_hwobj, "valueChanged", self.phi_motor_moved) - else: - logging.getLogger("HWR").error("ALBAMiniDiff: Phi motor is not defined") - - if self.phiz_motor_hwobj is not None: - self.connect( - self.phiz_motor_hwobj, "stateChanged", self.phiz_motor_state_changed - ) - self.connect(self.phiz_motor_hwobj, "valueChanged", self.phiz_motor_moved) - else: - logging.getLogger("HWR").error("ALBAMiniDiff: Phiz motor is not defined") - - if self.phiy_motor_hwobj is not None: - self.connect( - self.phiy_motor_hwobj, "stateChanged", self.phiy_motor_state_changed - ) - self.connect(self.phiy_motor_hwobj, "valueChanged", self.phiy_motor_moved) - else: - logging.getLogger("HWR").error("ALBAMiniDiff: Phiy motor is not defined") - - if self.zoom_motor_hwobj is not None: - self.connect( - self.zoom_motor_hwobj, "valueChanged", self.zoom_position_changed - ) - self.connect( - self.zoom_motor_hwobj, - "predefinedPositionChanged", - self.zoom_motor_predefined_position_changed, - ) - self.connect( - self.zoom_motor_hwobj, "stateChanged", self.zoom_motor_state_changed - ) - else: - logging.getLogger("HWR").error("ALBAMiniDiff: Zoom motor is not defined") - - if self.sample_x_motor_hwobj is not None: - self.connect( - self.sample_x_motor_hwobj, - "stateChanged", - self.sampleX_motor_state_changed, - ) - self.connect( - self.sample_x_motor_hwobj, "valueChanged", self.sampleX_motor_moved - ) - else: - logging.getLogger("HWR").error("ALBAMiniDiff: Sampx motor is not defined") - - if self.sample_y_motor_hwobj is not None: - self.connect( - self.sample_y_motor_hwobj, - "stateChanged", - self.sampleY_motor_state_changed, - ) - self.connect( - self.sample_y_motor_hwobj, "valueChanged", self.sampleY_motor_moved - ) - else: - logging.getLogger("HWR").error("ALBAMiniDiff: Sampx motor is not defined") - - if self.focus_motor_hwobj is not None: - self.connect(self.focus_motor_hwobj, "valueChanged", self.focus_motor_moved) - - GenericDiffractometer.init(self) - - queue_model_objects.CentredPosition.set_diffractometer_motor_names( - "phi", "phiy", "phiz", "sampx", "sampy", "kappa" - ) - - def state_changed(self, state): - """ - Overides method to map Tango ON state to Difractaometer State Ready. - - @state: Tango state - """ - - if str(state) == "ON": - state = DiffractometerState.tostring(DiffractometerState.Ready) - - if state != self.current_state: - logging.getLogger("HWR").debug( - "ALBAMinidiff: State changed %s (was: %s)" - % (str(state), self.current_state) - ) - self.current_state = state - self.emit("minidiffStateChanged", (self.current_state)) - - def getCalibrationData(self, offset=None): - """ - Get pixel size for OAV system - - @offset: Unused - @return: 2-tuple float - """ - calibx, caliby = self.calibration.getCalibration() - return 1000.0 / caliby, 1000.0 / caliby - # return 1000./self.md2.CoaxCamScaleX, 1000./self.md2.CoaxCamScaleY - - def get_pixels_per_mm(self): - """ - Returns the pixel/mm for x and y. Overrides GenericDiffractometer method. - """ - px_x, px_y = self.getCalibrationData() - return (px_x, px_y) - - def update_pixels_per_mm(self, *args): - """ - Emit signal with current pixel/mm values. - """ - self.pixels_per_mm_x, self.pixels_per_mm_y = self.getCalibrationData() - self.emit("pixelsPerMmChanged", ((self.pixels_per_mm_x, self.pixels_per_mm_y),)) - - # TODO: looks quite bizarre. - def motor_positions_to_screen(self, centred_positions_dict): - """ - Convert motor positions contained in a dictionary to screen (canvas) positions. - Overrides GenericDiffractometer method. - - @centered_positions_dict: dictionary to be converted - @return: position - """ - c = centred_positions_dict - - # if self.head_type == GenericDiffractometer.HEAD_TYPE_MINIKAPPA: - # kappa = self.motor_hwobj_dict["kappa"] - # phi = self.motor_hwobj_dict["kappa_phi"] - - xy = self.centring_hwobj.centringToScreen(c) - if xy is None: - return None - - x = xy["X"] * self.pixels_per_mm_x + self.zoom_centre["x"] - - y = xy["Y"] * self.pixels_per_mm_y + self.zoom_centre["y"] - - # logging.getLogger("HWR").debug(" motor_positions_to_screen ") - # logging.getLogger("HWR").debug(" positions = %s " % str(centred_positions_dict)) - # logging.getLogger("HWR").debug(" x,y = %s, %s " % (x,y)) - - return x, y - - # TODO: Must be implemented correctly. - def get_centred_point_from_coord(self, x, y, return_by_names=None): - """ - Returns a dictionary with motors name ans positions centred. - It is expected in start_move_to_beam and move_to_beam methods in - GenericDIffractometer HwObj. - - @return: dict - """ - return {"omega": [200, 200]} - - def getBeamInfo(self, update_beam_callback): - """ - Update beam info (position and shape) ans execute callback. - - @update_beam_callback: callback method passed as argument. - """ - calibx, caliby = self.calibration.getCalibration() - - size_x = self.get_channel_object("beamInfoX").get_value() / 1000.0 - size_y = self.get_channel_object("beamInfoY").get_value() / 1000.0 - - data = {"size_x": size_x, "size_y": size_y, "shape": "ellipse"} - - update_beam_callback(data) - - # TODO:Implement dynamically - def use_sample_changer(self): - """ - Overrides GenericDiffracometer method. - """ - return True - - # TODO:Implement dynamically - def in_plate_mode(self): - """ - Overrides GenericDiffracometer method. - """ - return False - - # We are using the sample_centring module. this is not used anymore - def start_manual_centring(self, *args, **kwargs): - """ - Start manual centring. Overrides GenericDiffracometer method. - Prepares diffractometer for manual centring. - """ - if self.prepare_centring(): - GenericDiffractometer.start_manual_centring(self, *args, **kwargs) - else: - logging.getLogger("HWR").info( - " Failed to prepare diffractometer for centring" - ) - self.invalidate_centring() - - def start_auto_centring(self, *args, **kwargs): - """ - Start manual centring. Overrides GenericDiffracometer method. - Prepares diffractometer for manual centring. - """ - if self.prepare_centring(): - GenericDiffractometer.start_auto_centring(self, *args, **kwargs) - else: - logging.getLogger("HWR").info( - " Failed to prepare diffractometer for centring" - ) - self.invalidate_centring() - - def prepare_centring(self): - """ - Prepare beamline for to sample_view phase. - """ - if not self.is_sample_view_phase(): - logging.getLogger("HWR").info( - " Not in sample view phase. Asking supervisor to go" - ) - success = self.go_sample_view() - if not success: - logging.getLogger("HWR").info("Cannot set SAMPLE VIEW phase") - return False - - return True - - # def manual_centring(self): - # """ - # We are using the sample_centring module. this is not used anymore - # """ - # self.centring_hwobj.initCentringProcedure() - - # # self.head_type = self.chan_head_type.get_value() - # # Say diffractometer to go to SampleView phase - - # # go to sample_view phase - # if not self.is_sample_view_phase(): - # logging.getLogger("HWR").info(" Not in sample view phase. Asking supervisor to go") - # success = self.go_sample_view() - # if not success: - # logging.getLogger("HWR").info("Cannot set SAMPLE VIEW phase") - # return False - - # phi_init_position = self.phi_motor_hwobj.get_value() - - # for click in range(3): - # self.user_clicked_event = gevent.event.AsyncResult() - # x, y = self.user_clicked_event.get() - # self.centring_hwobj.appendCentringDataPoint( - # {"X": (x - self.zoom_centre['x'])/ self.pixels_per_mm_x, - # "Y": (y - self.zoom_centre['y'])/ self.pixels_per_mm_y}) - - # if self.in_plate_mode(): - # dynamic_limits = self.phi_motor_hwobj.get_dynamic_limits() - # if click == 0: - # self.phi_motor_hwobj.set_value(dynamic_limits[0]) - # elif click == 1: - # self.phi_motor_hwobj.set_value(dynamic_limits[1]) - # else: - # if click < 2: - # self.phi_motor_hwobj.set_value_relative(-90, timeout=None) - - # #logging.getLogger("HWR").info(" Returning phi to initial position %s" % phi_init_position) - # #self.phi_motor_hwobj.set_value(phi_init_position, timeout=None) - # - # return self.centring_hwobj.centeredPosition(return_by_name=False) - - def is_sample_view_phase(self): - """ - Returns boolean by comparing the supervisor current phase and SAMPLE view phase. - - @return: boolean - """ - return self.super_hwobj.get_current_phase().upper() == "SAMPLE" - - def go_sample_view(self): - """ - Go to sample view phase. - """ - self.super_hwobj.go_sample_view() - - while True: - super_state = str(self.super_hwobj.get_state()).upper() - if super_state != "MOVING": - logging.getLogger("HWR").debug( - "ALBAMinidiff: go_sample_view done . super_state is %s" - % super_state - ) - return True - gevent.sleep(0.2) - - def supervisor_state_changed(self, state): - """ - Emit stateChanged signal according to supervisor current state. - """ - return - self.current_state = state - self.emit("stateChanged", (self.current_state,)) - - # TODO: Review override current_state by current_phase - def supervisor_phase_changed(self, phase): - """ - Emit stateChanged signal according to supervisor current phase. - """ - # self.current_state = phase - self.emit("minidiffPhaseChanged", (phase,)) - - def phi_motor_moved(self, pos): - """ - Emit phiMotorMoved signal with position value. - """ - self.current_motor_positions["phi"] = pos - # self.emit_diffractometer_moved() - self.emit("phiMotorMoved", pos) - # self.emit('stateChanged', (self.current_motor_states["phi"], )) - - def phi_motor_state_changed(self, state): - """ - Emit stateChanged signal with state value. - """ - self.current_motor_states["phi"] = state - self.emit("stateChanged", (state,)) - - def phiz_motor_moved(self, pos): - """ - """ - self.current_motor_positions["phiz"] = pos - # if time.time() - self.centring_time > 3.0: - # self.invalidate_centring() - # self.emit_diffractometer_moved() - - def phiz_motor_state_changed(self, state): - """ - Emit stateChanged signal with state value. - """ - self.emit("stateChanged", (state,)) - - def phiy_motor_state_changed(self, state): - """ - Emit stateChanged signal with state value. - """ - self.emit("stateChanged", (state,)) - - def phiy_motor_moved(self, pos): - """ - """ - self.current_motor_positions["phiy"] = pos - # if time.time() - self.centring_time > 3.0: - # self.invalidate_centring() - # self.emit_diffractometer_moved() - - def zoom_position_changed(self, value): - """ - Update positions after zoom changed. - - @value: zoom position. - """ - self.update_pixels_per_mm() - self.current_motor_positions["zoom"] = value - self.refresh_omega_reference_position() - - def zoom_motor_predefined_position_changed(self, position_name, offset): - """ - Update pixel size and emit signal. - """ - self.update_pixels_per_mm() - self.emit("zoomMotorPredefinedPositionChanged", (position_name, offset)) - - def zoom_motor_state_changed(self, state): - """ - Emit signal for motor zoom changed - - @state: new state value to emit. - """ - self.emit("stateChanged", (state,)) - - def sampleX_motor_moved(self, pos): - """ - """ - self.current_motor_positions["sampx"] = pos - # if time.time() - self.centring_time > 3.0: - # self.invalidate_centring() - # self.emit_diffractometer_moved() - - def sampleX_motor_state_changed(self, state): - """ - Emit stateChanged signal with state value. - """ - self.current_motor_states["sampx"] = state - self.emit("stateChanged", (state,)) - - def sampleY_motor_moved(self, pos): - """ - """ - self.current_motor_positions["sampy"] = pos - # if time.time() - self.centring_time > 3.0: - # self.invalidate_centring() - # self.emit_diffractometer_moved() - - def sampleY_motor_state_changed(self, state): - """ - Emit stateChanged signal with state value. - """ - self.current_motor_states["sampy"] = state - self.emit("stateChanged", (state,)) - - def focus_motor_moved(self, pos): - """ - """ - self.current_motor_positions["focus"] = pos - - # TODO: The command is not configured in the xml. Unused - def start_auto_focus(self): - self.cmd_start_auto_focus() - - def move_omega(self, pos, velocity=None): - """ - Move omega to absolute position. - - @pos: target position - """ - # turn it on - if velocity is not None: - self.phi_motor_hwobj.set_velocity(velocity) - self.phi_motor_hwobj.set_value(pos) - time.sleep(0.2) - # it should wait here - - def move_omega_relative(self, relpos): - """ - Move omega to relative position. - - @relpos: target relative position - """ - self.wait_device_ready() - self.phi_motor_hwobj.set_value_relative(relpos, timeout=None) - - # TODO: define phases as enum members. - def set_phase(self, phase): - """ - General function to set phase by using supervisor commands. - """ - if phase == "Transfer": - self.super_hwobj.go_transfer() - elif phase == "Collect": - self.super_hwobj.go_collect() - elif phase == "BeamView": - self.super_hwobj.go_beam_view() - elif phase == "Centring": - self.super_hwobj.go_sample_view() - else: - logging.getLogger("HWR").warning( - "Diffractometer set_phase asked for un-handled phase: %s" % phase - ) - - -def test_hwo(hwo): - print(hwo.get_phase_list()) diff --git a/mxcubecore/HardwareObjects/ALBA/ALBAPilatus.py b/mxcubecore/HardwareObjects/ALBA/ALBAPilatus.py deleted file mode 100644 index a39b24a80f..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBAPilatus.py +++ /dev/null @@ -1,290 +0,0 @@ -# -# 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 __future__ import print_function -import logging -import time - -from mxcubecore.HardwareObjects.abstract.AbstractDetector import ( - AbstractDetector, -) -from mxcubecore.BaseHardwareObjects import HardwareObject - -from PyTango.gevent import DeviceProxy - -__author__ = "Vicente Rey" -__credits__ = ["ALBA"] -__version__ = "2.3." -__category__ = "General" - - -class ALBAPilatus(AbstractDetector, HardwareObject): - """Detector class. Contains all information about detector - - states are 'OK', and 'BAD' - - status is busy, exposing, ready, etc. - - physical property is RH for pilatus, P for rayonix - """ - - def __init__(self, name): - AbstractDetector.__init__(self) - HardwareObject.__init__(self, name) - - self.distance_motor_hwobj = None - self.default_distance = None - self.default_distance_limits = None - - self.default_latency_time = 0.003 - - self.exp_time_limits = None - - self.headers = {} - - def init(self): - self.distance_motor_hwobj = self.get_object_by_role("distance_motor") - self.devname = self.get_property("tangoname") - - try: - self.latency_time = float(self.get_property("latency_time")) - except Exception: - self.latency_time = None - - if self.latency_time is None: - logging.getLogger("HWR").debug( - "Cannot obtain latency time from Pilatus XML. Using %s" - % self.default_latency_time - ) - self.latency_time = self.default_latency_time - - self.devspecific = self.get_property("device_specific") - - exp_time_limits = self.get_property("exposure_limits") - self.exp_time_limits = map(float, exp_time_limits.strip().split(",")) - - self.device = DeviceProxy(self.devname) - self.device_specific = DeviceProxy(self.devspecific) - self.device.set_timeout_millis(30000) - - self.beamx_chan = self.get_channel_object("beamx") - self.beamy_chan = self.get_channel_object("beamy") - - def start_acquisition(self): - self.device.startAcq() - - def stop_acquisition(self): - self.device.abortAcq() - - def wait_move_distance_done(self): - self.distance_motor_hwobj.wait_end_of_move() - - def get_threshold(self): - return self.device_specific.threshold - - def get_threshold_gain(self): - return self.device_specific.threshold_gain - - def has_shutterless(self): - """Return True if has shutterless mode""" - return True - - def get_beam_position(self, distance=None, wavelength=None): - """Returns beam center coordinates""" - beam_x = 0 - beam_y = 0 - try: - beam_x = self.beamx_chan.get_value() - beam_y = self.beamy_chan.get_value() - except Exception: - pass - return beam_x, beam_y - - def get_manufacturer(self): - return self.get_property("manufacturer") - return "Dectris" - - def get_model(self): - return self.get_property("model") - - def get_detector_type(self): - return self.get_property("type") - - def get_default_exposure_time(self): - return self.get_property("default_exposure_time") - - def get_minimum_exposure_time(self): - return self.get_property("minimum_exposure_time") - - def get_exposure_time_limits(self): - """Returns exposure time limits as list with two floats""" - return self.exp_time_limits - - def get_file_suffix(self): - return self.get_property("file_suffix") - - def get_pixel_size(self): - return self.get_property("px"), self.get_property("py") - - # methods for data collection - def set_energy_threshold(self): - eugap_ch = self.get_channel_object("eugap") - - try: - currentenergy = eugap_ch.get_value() - except Exception: - currentenergy = 12.6 - - det_energy = self.get_threshold() - - # threshold = det_energy / 2. - # limitenergy = threshold / 0.8 - - if round(currentenergy, 6) < 7.538: - currentenergy = 7.538 - - kev_diff = abs(det_energy - currentenergy) - - if kev_diff > 1.2: - logging.getLogger("HWR").debug( - "programming energy_threshold on pilatus to: %s" % currentenergy - ) - # if self.wait_standby(): - # self.device_specific.energy_threshold = currentenergy - - def get_latency_time(self): - return self.latency_time - - def wait_standby(self, timeout=300): - t0 = time.time() - while self.device_specific.cam_state == "STANDBY": - if time.time() - t0 > timeout: - print("timeout waiting for Pilatus to be on STANDBY") - return False - time.sleep(0.1) - return True - - def prepare_acquisition(self, dcpars): - - self.set_energy_threshold() - # self.wait_standby() - - osc_seq = dcpars["oscillation_sequence"][0] - file_pars = dcpars["fileinfo"] - - basedir = file_pars["directory"] - prefix = "%s_%s_" % (file_pars["prefix"], file_pars["run_number"]) - - first_img_no = osc_seq["start_image_number"] - nb_frames = osc_seq["number_of_images"] - exp_time = osc_seq["exposure_time"] - - fileformat = "CBF" - trig_mode = "EXTERNAL_TRIGGER" - # latency_time = 0.003 - - logging.getLogger("HWR").debug( - " Preparing detector (dev=%s) for data collection" % self.devname - ) - - logging.getLogger("HWR").debug(" /saving directory: %s" % basedir) - logging.getLogger("HWR").debug(" /prefix : %s" % prefix) - logging.getLogger("HWR").debug(" /saving_format : %s" % fileformat) - logging.getLogger("HWR").debug(" /trigger_mode : %s" % trig_mode) - logging.getLogger("HWR").debug(" /acq_nb_frames : %s" % nb_frames) - logging.getLogger("HWR").debug( - " /acq_expo_time : %s" % str(exp_time - self.latency_time) - ) - logging.getLogger("HWR").debug(" /latency_time : %s" % self.latency_time) - - self.device.write_attribute("saving_mode", "AUTO_FRAME") - self.device.write_attribute("saving_directory", basedir) - self.device.write_attribute("saving_prefix", prefix) - self.device.write_attribute("saving_format", fileformat) - - # set ROI and header in limaserver - # TODO - - TrigList = [ - "INTERNAL_TRIGGER", - "EXTERNAL_TRIGGER", - "EXTERNAL_TRIGGER_MULTI", - "EXTERNAL_GATE", - "EXTERNAL_START_STOP", - ] - - self.device.write_attribute("acq_trigger_mode", trig_mode) - self.device.write_attribute("acq_expo_time", exp_time - self.latency_time) - self.device.write_attribute("latency_time", self.latency_time) - - return True - - def prepare_collection(self, nb_frames, first_img_no): - logging.getLogger("HWR").debug( - "ALBAPilatus. preparing collection. nb_images: %s, first_no: %s" - % (nb_frames, first_img_no) - ) - self.device.write_attribute("acq_nb_frames", nb_frames) - self.device.write_attribute("saving_next_number", first_img_no) - self.device.prepareAcq() - return True - - def start_collection(self): - self.start_acquisition() - - def stop_collection(self): - self.stop_acquisition() - - def set_image_headers(self, image_headers, angle_info): - - nb_images = image_headers["nb_images"] - angle_inc = image_headers["Angle_increment"] - start_angle = image_headers["Start_angle"] - - startangles_list = list() - ang_start, ang_inc, spacing = angle_info - for i in range(nb_images): - startangles_list.append("%0.4f deg." % (ang_start + spacing * i)) - - headers = list() - for i, sa in enumerate(startangles_list): - header = ( - "_array_data.header_convention PILATUS_1.2\n" - "# Detector: PILATUS 6M, S/N 60-0108, Alba\n" - "# %s\n" - "# Pixel_size 172e-6 m x 172e-6 m\n" - "# Silicon sensor, thickness 0.000320 m\n" - % time.strftime("%Y/%b/%d %T") - ) - - # Acquisition values (headers dictionary) but overwrites start angle - image_headers["Start_angle"] = sa - for key, value in image_headers.items(): - if key == "nb_images": - continue - header += "# %s %s\n" % (key, value) - headers.append("%d : array_data/header_contents|%s;" % (i, header)) - - self.device.write_attribute("saving_header_delimiter", ["|", ";", ":"]) - self.device.resetCommonHeader() - self.device.resetFrameHeaders() - self.device.setImageHeader(headers) - - -def test_hwo(hwo): - print("Detector Distance is: ", hwo.distance.get_value()) - print(" Beam X: %s / Beam Y: %s" % hwo.get_beam_position()) - # print("going to 490 : ", hwo.distance.set_value(490)) diff --git a/mxcubecore/HardwareObjects/ALBA/ALBASession.py b/mxcubecore/HardwareObjects/ALBA/ALBASession.py deleted file mode 100644 index c01382306d..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBASession.py +++ /dev/null @@ -1,71 +0,0 @@ -import os -import time -import logging - -from mxcubecore.HardwareObjects import Session -from mxcubecore.HardwareObjects import queue_model_objects - - -class ALBASession(Session.Session): - def get_base_data_directory(self): - """ - Returns the base data directory for ALBA - In ALBA the base directory already includes the user - home directory. So - information into account, such as if the current user - is inhouse. - - :returns: The base data path. - :rtype: str - """ - if self.session_start_date: - start_time = self.session_start_date.split(" ")[0].replace("-", "") - else: - start_time = time.strftime("%Y%m%d") - - # directory = os.path.join(self.base_directory, self.get_proposal(), 'DATA', start_time) - if self.base_directory is not None: - directory = os.path.join(self.base_directory, start_time) - else: - directory = "/tmp" - return directory - - def get_archive_directory(self, directory=None): - if directory is None: - thedir = self.get_base_data_directory() - else: - thedir = directory - - parts = thedir.split(os.path.sep) - user_dir = parts[5] - session_date = parts[6] - # remove RAW_DATA from da - try: - more = parts[8:] - except Exception: - more = [] - - archive_dir = os.path.join( - self.base_archive_directory, user_dir, session_date, *more - ) - # if 'RAW_DATA' in thedir: - # thedir = thedir.replace('RAW_DATA','ARCHIVE') - # else: - # thedir = os.path.join(thedir, 'ARCHIVE') - - logging.getLogger("HWR").debug( - "ALBASession. returning archive directory: %s" % archive_dir - ) - return archive_dir - - def set_ldap_homedir(self, homedir): - self.base_directory = homedir - self.base_process_directory = homedir - - queue_model_objects.PathTemplate.set_data_base_path(self.base_directory) - - -def test_hwo(hwo): - print(hwo.get_base_data_directory()) - print(hwo.get_process_directory()) - print(hwo.get_archive_directory()) diff --git a/mxcubecore/HardwareObjects/ALBA/ALBASupervisor.py b/mxcubecore/HardwareObjects/ALBA/ALBASupervisor.py deleted file mode 100644 index 42074ef1c1..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBASupervisor.py +++ /dev/null @@ -1,76 +0,0 @@ -from mxcubecore import HardwareRepository as HWR -from mxcubecore.BaseHardwareObjects import Device -import logging - - -class ALBASupervisor(Device): - def __init__(self, *args): - Device.__init__(self, *args) - - def init(self): - self.state_chan = self.get_channel_object("state") - self.go_collect_cmd = self.get_command_object("go_collect") - self.go_sample_view_cmd = self.get_command_object("go_sample_view") - self.go_transfer_cmd = self.get_command_object("go_transfer") - self.go_beam_view_cmd = self.get_command_object("go_beam_view") - - self.phase_chan = self.get_channel_object("phase") - self.detector_cover_chan = self.get_channel_object("detector_cover_open") - - self.state_chan.connect_signal("update", self.state_changed) - self.phase_chan.connect_signal("update", self.phase_changed) - self.detector_cover_chan.connect_signal("update", self.detector_cover_changed) - - def is_ready(self): - return True - - def getUserName(self): - return self.username - - def state_changed(self, value): - self.current_state = value - self.emit("stateChanged", self.current_state) - - def phase_changed(self, value): - if value == "Sample": - value = "Centring" - self.current_phase = value - self.emit("phaseChanged", self.current_phase) - - def get_current_phase(self): - return self.phase_chan.get_value() - - def go_collect(self): - return self.go_collect_cmd() - - def go_transfer(self): - return self.go_transfer_cmd() - - def go_sample_view(self): - return self.go_sample_view_cmd() - - def go_beam_view(self): - return self.go_beam_view_cmd() - - def get_state(self): - return self.state_chan.get_value() - - def detector_cover_changed(self, value): - self.detector_cover_opened = value - # self.emit('levelChanged', self.current_level) - - def open_detector_cover(self): - self.detector_cover_chan.set_value(True) - - def close_detector_cover(self, value): - self.detector_cover_chan.set_value(False) - - def is_detector_cover_opened(self): - return self.detector_cover_chan.get_value() - - -def test_hwo(hwo): - print('\nSupervisor control "%s"\n' % hwo.getUserName()) - print(" Detector Cover opened:", hwo.is_detector_cover_opened()) - print(" Current Phase is:", hwo.get_current_phase()) - print(" Current State is:", str(hwo.get_state())) diff --git a/mxcubecore/HardwareObjects/ALBA/ALBATransmission.py b/mxcubecore/HardwareObjects/ALBA/ALBATransmission.py deleted file mode 100644 index a1aaf1041f..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBATransmission.py +++ /dev/null @@ -1,44 +0,0 @@ -from mxcubecore import HardwareRepository as HWR -from mxcubecore.BaseHardwareObjects import Device - - -class ALBATransmission(Device): - def __init__(self, *args): - Device.__init__(self, *args) - self.transmission = None - - def init(self): - self.transmissionChannel = self.get_channel_object("transmission") - self.stateChannel = self.get_channel_object("state") - - self.transmissionChannel.connect_signal("update", self.transmissionChanged) - self.stateChannel.connect_signal("update", self.stateChanged) - - def is_ready(self): - return True - - def transmissionChanged(self, value): - self.transmission = value - self.emit("attFactorChanged", self.transmission) - - def stateChanged(self, value): - self.state = str(value) - self.emit("attStateChanged", self.state) - - def getAttState(self): - self.state = self.stateChannel.get_value() - return self.state - - def get_value(self): - return self.transmissionChannel.get_value() - - def _set_value(self, value): - self.transmissionChannel.set_value(value) - - def re_emit_values(self): - value = self.get_value() - self.emit("attFactorChanged", value) - - -def test_hwo(hwo): - print("Transmission is: ", hwo.get_value()) diff --git a/mxcubecore/HardwareObjects/ALBA/ALBAZoomMotor.py b/mxcubecore/HardwareObjects/ALBA/ALBAZoomMotor.py deleted file mode 100755 index fa1ab2774d..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBAZoomMotor.py +++ /dev/null @@ -1,191 +0,0 @@ -# -# 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 . - -""" -[Name] -ALBAZoomMotor - -[Description] -Hardware Object is used to manipulate the zoom of the OAV camera. - -[Channels] -- position -- state -- labels - -[Commands] - -[Emited signals] -- stateChanged -- predefinedPositionChanged - -[Functions] -- None - -[Included Hardware Objects] -- None - -Example Hardware Object XML file : -================================== - - Zoom - ioregister/eh_zoom_tangoior_ctrl/2 - zoom - Zoom - Value - State - Labels - 200 - 0.001 - -""" - -from mxcubecore import BaseHardwareObjects -from mxcubecore.HardwareObjects.abstract.AbstractMotor import AbstractMotor -import logging -import PyTango - -__author__ = "Bixente Rey" -__credits__ = ["MXCuBE collaboration"] - -__version__ = "2.2." -__maintainer__ = "Jordi Andreu" -__email__ = "jandreu[at]cells.es" -__status__ = "Draft" - - -class ALBAZoomMotor(BaseHardwareObjects.Device, AbstractMotor): - - INIT, FAULT, READY, MOVING, ONLIMIT = range(5) - - def __init__(self, name): - BaseHardwareObjects.Device.__init__(self, name) - - def init(self): - logging.getLogger("HWR").debug("Initializing zoom motor IOR") - self.positionChannel = self.get_channel_object("position") - self.stateChannel = self.get_channel_object("state") - self.labelsChannel = self.get_channel_object("labels") - self.currentposition = 0 - self.currentstate = None - - self.positionChannel.connect_signal("update", self.positionChanged) - self.stateChannel.connect_signal("update", self.stateChanged) - - def get_predefined_positions_list(self): - labels = self.labelsChannel.get_value() - labels = labels.split() - retlist = [] - for label in labels: - # label, pos = label.split(":") - # retlist.append(int(pos)) - pos = str(label.replace(":", " ")) - retlist.append(pos) - logging.getLogger("HWR").debug("Zoom positions list: %s" % repr(retlist)) - new_retlist = [] - for n, e in enumerate(retlist): - name = e.split() - new_retlist.append("%s %s" % (n + 1, name[0])) - logging.getLogger("HWR").debug("Zoom positions list: %s" % repr(new_retlist)) - - # retlist = ["z1 1","z2 2"] - # logging.getLogger("HWR").debug("Zoom positions list: %s" % repr(retlist)) - return new_retlist - - def moveToPosition(self, posno): - no = posno.split()[0] - logging.getLogger("HWR").debug("type %s" % type(no)) - # no = posno - logging.getLogger("HWR").debug("Moving to position %s" % no) - state = self.positionChannel.set_value(int(no)) - - def motorIsMoving(self): - if str(self.get_state()) == "MOVING": - return True - else: - return False - - def get_limits(self): - return (1, 12) - - def get_state(self): - state = self.stateChannel.get_value() - curr_pos = self.get_value() - if state == PyTango.DevState.ON: - return ALBAZoomMotor.READY - elif state == PyTango.DevState.MOVING or state == PyTango.DevState.RUNNING: - return ALBAZoomMotor.MOVING - elif curr_pos in self.get_limits(): - return ALBAZoomMotor.ONLIMIT - else: - return ALBAZoomMotor.FAULT - return state - - def get_value(self): - try: - return self.positionChannel.get_value() - except Exception: - return self.currentposition - - def get_current_position_name(self): - try: - n = int(self.positionChannel.get_value()) - value = "%s z%s" % (n, n) - logging.getLogger("HWR").debug( - "get_current_position_name: %s" % repr(value) - ) - return value - except Exception: - logging.getLogger("HWR").debug("cannot get name zoom value") - return None - - def stateChanged(self, state): - logging.getLogger("HWR").debug("stateChanged emitted: %s" % state) - the_state = self.get_state() - if the_state != self.currentstate: - self.currentstate = the_state - self.emit("stateChanged", (the_state,)) - - def positionChanged(self, currentposition): - previous_position = self.currentposition - self.currentposition = self.get_current_position_name() - if self.currentposition != previous_position: - logging.getLogger("HWR").debug( - "predefinedPositionChanged emitted: %s" % self.currentposition - ) - self.emit("predefinedPositionChanged", (self.currentposition, 0)) - - def is_ready(self): - state = self.get_state() - return state == ALBAZoomMotor.READY - - -def test_hwo(zoom): - - print(type(zoom.get_state())) - - print(" Zoom position is : ", zoom.get_value()) - print("Zoom position name is : ", zoom.get_current_position_name()) - print(" Moving : ", zoom.motorIsMoving()) - print(" State : ", zoom.get_state()) - print(" Positions : ", zoom.get_predefined_positions_list()) - - -if __name__ == "__main__": - test() diff --git a/mxcubecore/HardwareObjects/ALBA/ALBAZoomMotorAutoBrightness.py b/mxcubecore/HardwareObjects/ALBA/ALBAZoomMotorAutoBrightness.py deleted file mode 100755 index 4d0d8d5f38..0000000000 --- a/mxcubecore/HardwareObjects/ALBA/ALBAZoomMotorAutoBrightness.py +++ /dev/null @@ -1,171 +0,0 @@ -# -# 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 . - -""" -[Name] -ALBAZoomMotorAutoBrightness - -[Description] -Hardware Object is used to manipulate the zoom IOR and the -paired backlight intensity (slave IOR) - -[Channels] -- None - -[Commands] - -[Emited signals] -- stateChanged -- predefinedPositionChanged - -[Functions] -- None - -[Included Hardware Objects] -- zoom -- blight - -Example Hardware Object XML file : -================================== - - - - -""" - -from mxcubecore import BaseHardwareObjects -from mxcubecore.HardwareObjects.abstract.AbstractMotor import AbstractMotor -import logging - -__author__ = "Jordi Andreu" -__credits__ = ["MXCuBE collaboration"] - -__version__ = "2.2." -__maintainer__ = "Jordi Andreu" -__email__ = "jandreu[at]cells.es" -__status__ = "Draft" - - -class ALBAZoomMotorAutoBrightness(BaseHardwareObjects.Device, AbstractMotor): - - INIT, FAULT, READY, MOVING, ONLIMIT = range(5) - - def __init__(self, name): - BaseHardwareObjects.Device.__init__(self, name) - - def init(self): - logging.getLogger("HWR").debug("Initializing zoom motor autobrightness IOR") - - self.zoom = self.get_object_by_role("zoom") - self.blight = self.get_object_by_role("blight") - - self.zoom.positionChannel.connect_signal("update", self.positionChanged) - self.zoom.stateChannel.connect_signal("update", self.stateChanged) - - def get_predefined_positions_list(self): - retlist = self.zoom.get_predefined_positions_list() - logging.getLogger("HWR").debug("Zoom positions list: %s" % repr(retlist)) - return retlist - - def moveToPosition(self, posno): - # no = posno.split()[0] - # logging.getLogger("HWR").debug("Moving to position %s" % no) - - # self.blight.moveToPosition(posno) - self.zoom.moveToPosition(posno) - state = self.zoom.get_state() - # state = self.positionChannel.set_value(int(no)) - - def motorIsMoving(self): - return self.zoom.motorIsMoving() - - # if str(self.get_state()) == "MOVING": - # return True - # else: - # return False - - def get_limits(self): - # return (1,12) - return self.zoom.get_limits() - - def get_state(self): - # state = self.stateChannel.get_value() - # curr_pos = self.get_value() - # if state == PyTango.DevState.ON: - # return ALBAZoomMotor.READY - # elif state == PyTango.DevState.MOVING or state == PyTango.DevState.RUNNING: - # return ALBAZoomMotor.MOVING - # elif curr_pos in self.get_limits(): - # return ALBAZoomMotor.ONLIMIT - # else: - # return ALBAZoomMotor.FAULT - # return state - return self.zoom.get_state() - - def get_value(self): - return self.zoom.get_value() - - def get_current_position_name(self): - # n = int(self.positionChannel.get_value()) - # value = "%s z%s" % (n, n) - # logging.getLogger("HWR").debug("get_current_position_name: %s" % repr(value)) - # return value - return self.zoom.get_current_position_name() - - def stateChanged(self, state): - logging.getLogger("HWR").debug("stateChanged emitted: %s" % state) - self.emit("stateChanged", (self.get_state(),)) - - def positionChanged(self, currentposition): - currentposition = self.get_current_position_name() - logging.getLogger("HWR").debug( - "predefinedPositionChanged emitted: %s" % currentposition - ) - # Update light brightness step-by-step - posno = currentposition.split()[0] - logging.getLogger("HWR").debug("Moving brightness to: %s" % posno) - - self.blight.moveToPosition(posno) - - self.emit("predefinedPositionChanged", (currentposition, 0)) - - def is_ready(self): - state = self.get_state() - return state == ALBAZoomMotorAutoBrightness.READY - - -def test(): - from mxcubecore import HardwareRepository as HWR - - hwr = HWR.get_hardware_repository() - hwr.connect() - - zoom = hwr.get_hardware_object("/zoom-auto-brightness") - - print(type(zoom.get_state())) - - print(" Zoom position is : ", zoom.get_value()) - print("Zoom position name is : ", zoom.get_current_position_name()) - print(" Moving : ", zoom.motorIsMoving()) - print(" State : ", zoom.get_state()) - print(" Positions : ", zoom.get_predefined_positions_list()) - - -if __name__ == "__main__": - test() diff --git a/mxcubecore/HardwareObjects/ALBA/ALBABackLight.py b/mxcubecore/HardwareObjects/ALBA/XalocBackLight.py similarity index 52% rename from mxcubecore/HardwareObjects/ALBA/ALBABackLight.py rename to mxcubecore/HardwareObjects/ALBA/XalocBackLight.py index f13b75347e..373c1d7ce7 100644 --- a/mxcubecore/HardwareObjects/ALBA/ALBABackLight.py +++ b/mxcubecore/HardwareObjects/ALBA/XalocBackLight.py @@ -1,13 +1,56 @@ -from mxcubecore import HardwareRepository as HWR -from mxcubecore.BaseHardwareObjects import Device +# +# 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 . + +""" +[Name] +XalocBackLight + +[Description] +Hardware Object used to operate the diffractometer backlight. + +[Emitted signals] +- levelChanged +- stateChanged +""" + +#from __future__ import print_function + +import time import logging import gevent -import time + +from mxcubecore.BaseHardwareObjects import Device + +__credits__ = ["ALBA Synchrotron"] +__version__ = "3" +__category__ = "General" -class ALBABackLight(Device): +class XalocBackLight(Device): + def __init__(self, *args): Device.__init__(self, *args) + self.logger = logging.getLogger("HWR.XalocBackLight") + + self.backlightin_channel = None + self.level_channel = None + self.limits = [None, None] self.state = None self.current_level = None @@ -15,14 +58,18 @@ def __init__(self, *args): self.register_state = None self.memorized_level = None + self.rest_level = None self.default_rest_level = 0.0 - self.default_minimum_level = 7.0 + self.minimum_level = None + self.default_minimum_level = 30.0 def init(self): - + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) self.backlightin_channel = self.get_channel_object("backlightin") self.level_channel = self.get_channel_object("light_level") + self.set_name('backlight') + limits = self.get_property("limits") if limits is not None: @@ -48,62 +95,60 @@ def init(self): def is_ready(self): return True + + isReady = is_ready def level_changed(self, value): self.current_level = value - self.emit("levelChanged", self.current_level) + self.emit('levelChanged', self.current_level) def state_changed(self, value): + #self.logger.debug("Backlight state is %s" % value) state = value if state != self.state: self.state = state - if state: - self.emit("stateChanged", "on") - else: - self.emit("stateChanged", "off") + self.emit('stateChanged', value) def _current_state(self): - - state = None - if self.actuator_status: - state = "off" + return False else: - state = "on" - - return state + return True def get_limits(self): return self.limits def get_state(self): _state = self.backlightin_channel.get_value() - if _state: - return "on" + _level_on = self.level_channel.get_value() > 0 + if _state and _level_on: + return True else: - return "off" + return False - def getUserName(self): + def get_user_name(self): return self.username - def getLevel(self): + def get_level(self): self.current_level = self.level_channel.get_value() return self.current_level - def setLevel(self, level): + def set_level(self, level): self.level_channel.set_value(float(level)) - def setOn(self): + def set_on(self): + #self.logger.debug("backlight in %s", self.backlightin_channel.get_value() ) self.on_task = gevent.spawn(self._setOn) self.on_task.link(self._task_finished) self.on_task.link_exception(self._task_failed) def _setOn(self): if self.backlightin_channel.get_value() is False: + #self.logger.debug( "Set backlight in" ) self.set_backlight_in() wait_ok = self.wait_backlight_in() if not wait_ok: - logging.getLogger("HWR").debug("could not set backlight in") + self.logger.debug("Could not set backlight in") return level = None @@ -113,8 +158,8 @@ def _setOn(self): if not level or level < self.minimum_level: level = self.minimum_level - logging.getLogger("HWR").debug("setting light level to : %s" % level) - self.setLevel(level) + #self.logger.debug("Setting light level to : %s" % level) + self.set_level(level) def set_backlight_in(self): self.backlightin_channel.set_value(True) @@ -125,53 +170,37 @@ def wait_backlight_in(self, state=True, timeout=10): while elapsed < timeout: isin = self.backlightin_channel.get_value() if isin == state: - logging.getLogger("HWR").debug( - "waiting for backlight took %s . In is: %s" % (elapsed, isin) - ) + self.logger.debug( + "Waiting for backlight took %s. In is: %s" % + (elapsed, isin)) return True gevent.sleep(0.1) elapsed = time.time() - t0 - logging.getLogger("HWR").debug("Timeout waiting for backlight In") + self.logger.debug("Timeout waiting for backlight In") return False def _task_finished(self, g): - logging.getLogger("HWR").debug("Backlight task finished") + self.logger.debug("Backlight task finished") self._task = None def _task_failed(self, g): - logging.getLogger("HWR").debug("Backlight task failed") + self.logger.debug("Backlight task failed") self._task = None - def setOff(self): + def set_off(self): if self.current_level: self.memorized_level = self.current_level - self.setLevel(self.rest_level) + self.set_level(self.rest_level) self.backlightin_channel.set_value(False) + def re_emit_values(self): + self.emit("stateChanged", self.state ) + self.emit("levelChanged", self.current_level ) def test_hwo(hwo): - import sys - - print('\nLight control for "%s"\n' % hwo.getUserName()) - print(" Level limits are:", hwo.get_limits()) - print(" Current level is:", hwo.getLevel()) - print(" Current state is:", hwo.get_state()) - print(" Setting backlight in") - - print(sys.argv) - if sys.argv[3] == "0": - print("Setting backlight off") - n = False - hwo.setOff() - else: - print("Setting backlight on") - n = True - hwo.setOn() - - hwo.wait_backlight_in(state=n) - # while gevent.wait(timeout=0.1): - # print "Waiting" - # gevent.sleep(0.1) - - print(" Current state is:", hwo.get_state()) + + print("Light control for \"%s\"\n" % hwo.get_user_name()) + print("Level limits are:", hwo.get_limits()) + print("Current level is:", hwo.get_level()) + print("Current state is:", hwo.get_state()) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocBeam.py b/mxcubecore/HardwareObjects/ALBA/XalocBeam.py new file mode 100755 index 0000000000..7225f4b94c --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocBeam.py @@ -0,0 +1,157 @@ +# +# 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 . + +""" +[Name] BeamInfo + +[Description] +BeamInfo hardware object is used to define final beam size and shape. +It can include aperture, slits and/or other beam definer (lenses or other eq.) + +[Signals] +beamInfoChanged +beamSizeChanged +""" + +#from __future__ import print_function + +import logging +from mxcubecore.HardwareObjects.BeamInfo import BeamInfo +#from mxcubecore.HardwareObjects.abstract import AbstractBeam + +__credits__ = ["ALBA Synchrotron"] +__version__ = "3" +__category__ = "General" + + +class XalocBeam(BeamInfo): + + def __init__(self, *args): + BeamInfo.__init__(self, *args) + self.logger = logging.getLogger("HWR.XalocBeamInfo") + + self.chan_beam_width = None + self.chan_beam_height = None + self.chan_beam_posx = None + self.chan_beam_posy = None + + def init(self): + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + BeamInfo.init(self) + + self.chan_beam_width = self.get_channel_object("BeamWidth") + self.chan_beam_height = self.get_channel_object("BeamHeight") + self.chan_beam_posx = self.get_channel_object("BeamPositionHorizontal") + self.chan_beam_posy = self.get_channel_object("BeamPositionVertical") + + # Initialize these values BEFORE connecting the signals, they are needed in + self.beam_info_dict["size_x"] = self.chan_beam_width.get_value() / 1000. + self.beam_info_dict["size_y"] = self.chan_beam_height.get_value() / 1000. + self.logger.debug("self.beam_info_dict[\"size_x\"] %s" % self.beam_info_dict["size_x"] ) + self.logger.debug("self.beam_info_dict[\"size_y\"] %s" % self.beam_info_dict["size_y"] ) + + self.chan_beam_height.connect_signal('update', self.beam_height_changed) + self.chan_beam_width.connect_signal('update', self.beam_width_changed) + self.chan_beam_posx.connect_signal('update', self.beam_posx_changed) + self.chan_beam_posy.connect_signal('update', self.beam_posy_changed) + + self.beam_position = self.chan_beam_posx.get_value(),\ + self.chan_beam_posy.get_value() + + #def connect_notify(self, *args): + #self.evaluate_beam_info() + #self.emit_beam_info_changed() + + #def get_beam_divergence_hor(self): + #return self.default_beam_divergence[0] + + #def get_beam_divergence_ver(self): + #return self.default_beam_divergence[1] + + def get_beam_position(self): + self.beam_position = self.chan_beam_posx.get_value(),\ + self.chan_beam_posy.get_value() + return self.beam_position + + #def get_slits_gap(self): + #return None, None + + def set_beam_position(self, beam_x, beam_y): + self.beam_position = (beam_x, beam_y) + + def get_beam_info(self): + return self.evaluate_beam_info() + + #def get_beam_size(self): + #self.evaluate_beam_info() + #return self.beam_info_dict["size_x"], self.beam_info_dict["size_y"] + + #def get_beam_shape(self): + #return self.beam_info_dict["shape"] + + def beam_width_changed(self, value): + self.beam_info_dict['size_x'] = value / 1000. + #self.logger.debug("New beam width %.3f" % value) + + self.evaluate_beam_info() + self.emit_beam_info_changed() + + def beam_height_changed(self, value): + self.beam_info_dict['size_y'] = value / 1000. + self.evaluate_beam_info() + self.emit_beam_info_changed() + + def beam_posx_changed(self, value): + self.beam_position = ( value, self.beam_position[1] ) + self.emit_beam_info_changed() + + def beam_posy_changed(self, value): + self.beam_position = ( self.beam_position[0], value ) + self.emit_beam_info_changed() + + ##def evaluate_beam_info(self): + ##self.beam_info_dict["size_x"] = self.chan_beam_width.get_value() / 1000.0 + ##self.beam_info_dict["size_y"] = self.chan_beam_height.get_value() / 1000.0 + ##self.beam_info_dict["shape"] = "rectangular" + ##return self.beam_info_dict + + def get_beam_position_on_screen(self): + """Get the beam position + Returns: + (tuple): Position (x, y) [pixel] + """ + # TODO move this method to AbstractSampleView + # What is the difference between beam_position and beam_position_on_screen?? + #return self._beam_position_on_screen + return self.get_beam_position() + + def emit_beam_info_changed(self): + #self.logger.debug(" emitting beam info") + if self.beam_info_dict["size_x"] != 9999 and \ + self.beam_info_dict["size_y"] != 9999: + self.emit("beamSizeChanged", ((self.beam_info_dict["size_x"], + self.beam_info_dict["size_y"]), )) + self.emit("beamInfoChanged", (self.beam_info_dict, )) + + + + +def test_hwo(hwo): + print(hwo.get_beam_info()) + print(hwo.get_beam_position()) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocCats.py b/mxcubecore/HardwareObjects/ALBA/XalocCats.py new file mode 100755 index 0000000000..0b0fdf92c7 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocCats.py @@ -0,0 +1,1430 @@ +# +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] XalocCats + +[Description] +HwObj used to control the CATS sample changer via Tango. + +[Signals] +- powerStateChanged +- runningStateChanged + +Comments: +In case of failed put push button, CatsMaint calls the reset command in the DS +In case of failed get push button, CatsMaint calls the recoverFailure command in the DS +""" + +#from __future__ import print_function + +import logging +import time +import PyTango +import gevent + +from mxcubecore.HardwareObjects.Cats90 import Cats90, SampleChangerState#, TOOL_SPINE +from mxcubecore import HardwareRepository as HWR + +__credits__ = ["ALBA Synchrotron"] +__version__ = "3" +__category__ = "General" +__author__ = "Vicente Rey, Jordi Andreu, Roeland Boer" + +TIMEOUT = 3 +DOUBLE_GRIPPER_DRY_WAIT_TIME = 80 # time the double gripper takes in going from home to midway soak during a dry + +TOOL_FLANGE, TOOL_UNIPUCK, TOOL_SPINE, TOOL_PLATE, \ + TOOL_LASER, TOOL_DOUBLE_GRIPPER = (0,1,2,3,4,5) +BASKET_UNKNOWN, BASKET_SPINE, BASKET_UNIPUCK = (0, 1, 2) +# +# Number of samples per puck type +# +SAMPLES_SPINE = 10 +SAMPLES_UNIPUCK = 16 + +class XalocCats(Cats90): + """ + Main class used @ ALBA to integrate the CATS-IRELEC sample changer. + """ + + def __init__(self, *args, **kwargs): + Cats90.__init__(self, *args, **kwargs) + #super(XalocCats, self).__init__(self.__TYPE__, False, *args, **kwargs) + + self.logger = logging.getLogger("HWR.XalocCats") + self.detdist_saved = None + + self.shifts_channel = None + self.diff_phase_channel = None + self.diff_state_channel = None + self.detdist_position_channel = None + self.omega_position_channel = None + self.kappa_position_channel = None + self._chnisDetDistSafe = None + + self._chnCollisionSensorOK = None + self._chnIsCatsIdle = None + self._chnIsCatsHome = None + self._chnIsCatsRI1 = None + self._chnIsCatsRI2 = None + self._chnNBSoakings = None + self._chnLidSampleOnTool = None + self._chnNumSampleOnTool = None + self._chnPath = None + + self.diff_go_sampleview_cmd = None + self.super_go_sampleview_cmd = None + self.super_abort_cmd = None + + self._cmdLoadHT = None + self._cmdChainedLoadHT = None + self._cmdUnloadHT = None + self._cmdClearMemory = None + self._cmdSetTool = None + + self._cmdCATSRecovery = None + + self.cats_ri2 = None + + self.auto_prepare_diff = None + self.next_pick_sample_location = [-1,-1] + self.sample_can_be_centered = None + + self.sample_lid_on_tool = None + self.sample_num_on_tool = None + self.changing_tool = None + + self.logger.debug("unipuck_tool property = %s" % self.get_property("unipuck_tool") ) + + def init(self): + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + #Cats90.init(self) + super(XalocCats,self).init() + + # TODO: Migrate to taurus channels instead of tango channels + self.shifts_channel = self.get_channel_object("shifts") + self.diff_phase_channel = self.get_channel_object("diff_phase") + self.diff_state_channel = self.get_channel_object("diff_state") + self.detdist_position_channel = self.get_channel_object("detdist_position") + self.super_cryopos_channel = self.get_channel_object("super_cryo_position") + self.omega_position_channel = self.get_channel_object("omega_position") # position of the omega axis + self.kappa_position_channel = self.get_channel_object("kappa_position") # position of the kappa axis + self._chnisDetDistSafe = self.get_channel_object("DetDistanceSafe") + + self._chnCollisionSensorOK = self.get_channel_object("_chnCollisionSensorOK") + self._chnIsCatsIdle = self.get_channel_object( "_chnIsCatsIdle" ) + self._chnIsCatsHome = self.get_channel_object( "_chnIsCatsHome" ) + self._chnIsCatsRI1 = self.get_channel_object( "_chnIsCatsRI1" ) + self._chnIsCatsRI2 = self.get_channel_object( "_chnIsCatsRI2" ) + self._chnNBSoakings = self.get_channel_object( "_chnNBSoakings" ) + self._chnLidSampleOnTool = self.get_channel_object( "_chnLidSampleOnTool" ) + self._chnNumSampleOnTool = self.get_channel_object( "_chnNumSampleOnTool" ) + self._chnPath = self.get_channel_object( "_chnPath" ) + + self.diff_go_sampleview_cmd = self.get_command_object("diff_go_sampleview") + self.super_go_sampleview_cmd = self.get_command_object("super_go_sampleview") + self.super_abort_cmd = self.get_command_object("super_abort") + + self._cmdLoadHT = self.get_command_object("_cmdLoadHT") + self._cmdChainedLoadHT = self.get_command_object("_cmdChainedLoadHT") + self._cmdUnloadHT = self.get_command_object("_cmdUnloadHT") + self._cmdPick = self.get_command_object("_cmdPick") + self._cmdChainedLoadPick = self.get_command_object("_cmdChainedLoadPick") + + self._cmdClearMemory = self.get_command_object("_cmdClearMemory") + self._cmdSetTool = self.get_command_object("_cmdSetTool") + self._cmdSetTool2 = self.get_command_object("_cmdSetTool2") + + self._cmdCATSRecovery = self.get_command_object("macro_cats_recovery") + + self.auto_prepare_diff = self.get_property("auto_prepare_diff") + self.sample_can_be_centered = True + + self.logger.debug("unipuck_tool property = %s" % self.get_property("unipuck_tool") ) + + self.sample_lid_on_tool = -1 + self.sample_num_on_tool = -1 + + if self._chnPath is not None: + #self.current_path = self._chnPath.get_value() + self._chnPath.connect_signal("update", self._update_path) + + if self._chnPathRunning is not None: + self._chnPathRunning.connect_signal("update", self._update_running_state) + + if self._chnIsCatsRI2 is not None: + self._chnIsCatsRI2.connect_signal("update", self._cats_ri2_changed) + + if self._chnLidSampleOnTool is not None: + self._chnLidSampleOnTool.connect_signal("update", self.sample_lid_on_tool_changed) + + if self._chnNumSampleOnTool is not None: + self._chnNumSampleOnTool.connect_signal("update", self.sample_num_on_tool_changed) + + ret,msg = self._check_coherence() + if not ret: + logging.getLogger('user_level_log').warning( msg ) + + # quick fix to get Cats to accept the unipuck_tool + # the property is set in Cats90, but the property unipuck_tool is somehow not read properly + self.set_unipuck_tool(5) + + + #def cats_state_changed(self, value): + + #logging.getLogger("HWR").debug("Cats90 cats_state_changed chnState value is %s, value == PyTango.DevState.ON %s, type %s" % \ + #(str(value) , value == PyTango.DevState.ON, type(value) ) + #) + #timeout = 1 + #if self.cats_state != value: + ## hack for transient states + + #t0 = time.time() + #while value in [PyTango.DevState.ALARM, PyTango.DevState.ON]: + #time.sleep(0.1) + #self.logger.warning( + #"SAMPLE CHANGER could be in transient state (state is %s). trying again" + #% self.cats_state + #) + #value = self._chnState.get_value() + #if (time.time() - t0) > timeout: + ##self.logger.warning("SAMPLE CHANGER state change timed out %s)" % self.cats_state ) + ##logging.getLogger('user_level_log').error("SAMPLE CHANGER state is not ready") + #break + + #logging.getLogger("HWR").debug("Cats90. cats_state_changed, updating power state to %s " % value) + + #self.cats_state = value + #self._update_state() + + def _cats_ri2_changed(self, value): + logging.getLogger("HWR").debug("Cats ri2 change, is %s" % + str(value) + ) + + if value is not None: + self.cats_ri2 = value + + def is_ready(self): + """ + Returns a boolean value indicating is the sample changer is ready for operation. + + @return: boolean + """ + return self.state == SampleChangerState.Ready or \ + self.state == SampleChangerState.Loaded or \ + self.state == SampleChangerState.Charging or \ + self.state == SampleChangerState.StandBy or \ + self.state == SampleChangerState.Disabled + + def send_beamline_to_transfer(self, timeout = 36): + """ + Checks if beamline diff is in TRANSFER phase (i.e. sample changer in + TRANSFER phase too). If it is not the case, It sends the supervisor to TRANSFER + phase. Then waits for the minimal conditions of the beamline to start the transfer + + @return: boolean + """ + msg = "" + + if HWR.beamline.supervisor.is_detector_cover_opened(): + self.logger.debug("Closing detcover.") + HWR.beamline.supervisor.close_detector_cover() + + if HWR.beamline.supervisor.get_current_phase().upper() == "TRANSFER": # The cover is not taken into account for transfer phase + self.logger.debug("Supervisor is already in transfer phase") + else: + # First wait till the supervisor is ready to accept a sample transfer + try: + HWR.beamline.supervisor.wait_ready(timeout) + time.sleep(0.1) + HWR.beamline.supervisor.set_phase("TRANSFER") + except Exception as e: + msg = "Supervisor cannot get to transfer phase.\n %s" % str(e) + logging.getLogger("HWR").error( msg ) + return False,msg # a return False, in order to update the state in case of an Exception + + # To improve the speed of sample mounting, the wait for phase done was removed. + # Rationale: the time it takes the diff to go to transfer phase is about 7-9 seconds. + # The limiting factor is actually the detector safe position (-70), which takes 19.1 seconds to reach from the minimal distance + # The fastest mouting time with pick is in the 7-9 secs range, so mounting without pick + # will take much longer before arriving at the diff + # NOTE For pick mounting, a time sleep may be required. + # Another potentially limiting step is omega movement. At an max omega of 2160, it takes 36 seconds to reach 0 + # omega is somehow involved in calculating the diff mounting position, so omega should be at zero before continuing + # TODO check if we can improve the involvement of omega in the calculations. + # kappa should also be considered. Max kappa angle is 255, speed 17. Thus, at most kappa to zero takes 15 secs + #ret = self._wait_diff_phase_done('TRANSFER') + ret1 = self._wait_kappa_zero() + ret2 = self._wait_omega_zero() + ret3 = self._wait_det_safe() + if not ret1: msg = "Cannot move kappa to zero" + if not ret2: msg = "Cannot move omega to zero" + if not ret3: msg = "Cannot move detector to safety" + + return ( ret1 and ret2 and ret3 ), msg + + #TODO: remove and replace with diffractometer.wait_ready() + def _wait_diff_on(self, timeout = 36): + t0 = time.time() + while True: + state = self.diff_state_channel.get_value() + if state == PyTango.DevState.ON: + break + + if (time.time() - t0) > timeout: + self.logger.error("Diff timeout waiting for ON state. Returning") + return False + + return True + + def _wait_super_cryoposition_out(self, timeout = 2): + stime = time.time() + ret = False + while time.time() - stime < timeout: + cryopos = str(self.super_cryopos_channel.get_value()) + if cryopos.upper() == "SAMPOUT": + self.logger.debug("Cryo position is in SAMPOUT. Returning") + ret = True + break + time.sleep(0.02) + return ret + + def _wait_cats_idle(self): + while True: + if self._chnIsCatsIdle.get_value(): + self.logger.debug("_chnIsCatsIdle %s, type %s" % ( str(self._chnIsCatsIdle.get_value()), type(self._chnIsCatsIdle.get_value()) ) ) + self.logger.debug("CATS is idle. Returning") + break + time.sleep(0.2) + + def _wait_cats_home(self, timeout): + t0 = time.time() + while True: + if self._chnIsCatsHome.get_value(): + self.logger.debug("CATS is home. Returning") + break + time.sleep(0.2) + if time.time() - t0 > timeout: return False + + return True + + def _wait_det_safe(self, timeout=30): + t0 = time.time() + while True: + if self._chnisDetDistSafe.get_value(): + self.logger.debug("Detector is in a safe position. Returning") + break + time.sleep(0.2) + if time.time() - t0 > timeout: return False + + return True + + def _wait_kappa_zero(self, timeout = 15.): + #self.logger.debug("_wait_kappa_zero timeout %.2f kappa pos %.4f" % (timeout, self.kappa_position_channel.get_value() ) ) + t0 = time.time() + while True: + if abs( self.kappa_position_channel.get_value() ) < 0.1:# the error in position is very high (0.07 um) when starting from 2160 + self.logger.debug("kappa is zero. Returning") + break + time.sleep(0.5) + if time.time() - t0 > timeout: return False + + return True + + def _wait_omega_zero(self, timeout = 37.): + #self.logger.debug("_wait_omega_zero timeout %.2f omega pos %.4f" % (timeout, self.omega_position_channel.get_value() ) ) + t0 = time.time() + while True: + if abs( self.omega_position_channel.get_value() ) < 0.1:# the error in position is very high (0.07 um) when starting from 2160 + self.logger.debug("Omega is zero. Returning") + break + time.sleep(0.5) + if time.time() - t0 > timeout: return False + + return True + + def _wait_super_moving(self): + allokret = True # No problems + while allokret: + state = str( HWR.beamline.supervisor.get_state() ) + if not self._chnCollisionSensorOK.get_value(): + self._update_state() + raise Exception ("The robot had a collision, call your LC or floor coordinator") + elif state == "MOVING": + self.logger.debug("Supervisor is in MOVING state. Returning") + return allokret + time.sleep(0.1) + + return allokret + + def _wait_diff_phase_done(self, final_phase, timeout = 20 ): + """ + Method to wait a phase change. When supervisor reaches the final phase, the + method returns True. + + @final_phase: target phase + @return: boolean + """ + + t0 = time.time() + while self.read_diff_phase().upper() != final_phase: + state = self.diff_state_channel.get_value() + phase = self.read_diff_phase().upper() + if not state in [ PyTango.DevState.ON , PyTango.DevState.MOVING ]: + self.logger.error("Diff is in a funny state %s" % str(state)) + return False + + self.logger.debug("Diff waiting to finish phase change") + time.sleep(0.2) + if time.time() - t0 > timeout: break + + if self.read_diff_phase().upper() != final_phase: + self.logger.error("Diff is not yet in %s phase. Aborting load" % + final_phase) + return False + else: + self.logger.info( + "Diff is in %s phase. Beamline ready for the next step..." % + final_phase) + return True + + def _wait_phase_done(self, final_phase, timeout = 20 ): + """ + Method to wait a phase change. When supervisor reaches the final phase, the + method returns True. + + @final_phase: target phase + @return: boolean + """ + + t0 = time.time() + while HWR.beamline.supervisor.get_current_phase().upper() != final_phase: + state = str( HWR.beamline.supervisor.get_state() ) + phase = HWR.beamline.supervisor.get_current_phase().upper() + if not str(state) in [ "MOVING", "ON" ]: + self.logger.error("Supervisor is in a funny state %s" % str(state)) + return False + + self.logger.debug("Supervisor waiting to finish phase change") + time.sleep(0.2) + + t0 = time.time() + timeout = 5 + while HWR.beamline.supervisor.get_current_phase().upper() != final_phase or timeout > time.time() - t0: + logging.getLogger("HWR").warning( + "Phase changed done. Waiting phase change....") + time.sleep(0.2) + + if HWR.beamline.supervisor.get_current_phase().upper() != final_phase: + self.logger.error("Supervisor is not yet in %s phase. Aborting load" % + final_phase) + return False + else: + self.logger.info( + "Supervisor is in %s phase. Beamline ready to start sample loading..." % + final_phase) + return True + + def save_detdist_position(self): + self.detdist_saved = self.detdist_position_channel.get_value() + self.logger.error("Saving current det.distance (%s)" % self.detdist_saved) + + def restore_detdist_position(self): + if abs(self.detdist_saved - self.detdist_position_channel.get_value()) >= 0.1: + self.logger.error( + "Restoring det.distance to %s" % self.detdist_saved) + self.detdist_position_channel.set_value(self.detdist_saved) + + def read_diff_phase(self): + """ + Returns diff phase (CurrentPhase attribute from Beamline Diffractometer + TangoDS) + + @return: str + """ + return self.diff_phase_channel.get_value() + + def load(self, sample=None, wait=False): + """ + Loads a sample. Overides to include ht basket. + + @sample: sample to load. a string is passed with format "%d:%d" % (basketnr:samplenr) + @wait: + @wash: wash dring the load opearation. + @return: + """ + + sample_location_str = sample + self.sample_can_be_centered = True + + #self.logger.debug( + #"Loading sample %s / type(%s)" % + #( sample_location_str, type(sample_location_str) ) + #) + + ok, msg = self._check_incoherent_sample_info() + if not ok: + self.sample_can_be_centered = False + raise Exception(msg) + + sample_ht = self.is_ht_sample(sample_location_str) # sample number in HT basket + + if not sample_ht: + sample = self._resolve_component(sample_location_str) + self.assert_not_charging() + use_ht = False + else: + sample = sample_ht + use_ht = True + + # end some cancel cases + + if self.has_loaded_sample(): + if self.get_loaded_sample() == sample: + raise Exception( + "The sample %s is already loaded" % sample.get_address() + ) + + #self.logger.debug( + #"Loading sample %s / type(%s)" % + #( sample.get_address(), type(sample) ) + #) + + + # This runs the AbstractSampleChanger method! + ok = self._execute_task(SampleChangerState.Loading, + wait, self._do_load_xaloc, sample, use_ht) + #if not ok: self.sample_can_be_centered = False + + if ok: HWR.beamline.diffractometer.sample_has_been_centred = False + + return ok + + def unload(self, sample_slot=None, shifts=None, wait=False): + """ + Unload the sample. If sample_slot=None, unloads to the same slot the sample was + loaded from. + + @sample_slot: + @wait: + @return: + """ + + self.sample_can_be_centered = True + + sample_slot = self._resolve_component(sample_slot) + + self.assert_not_charging() + + # In case we have manually mounted we can command an unmount + if not self.has_loaded_sample(): + self.sample_can_be_centered = False + raise Exception("No sample is loaded") + + # This runs the AbstractSampleChanger method! + ok = self._execute_task(SampleChangerState.Unloading, + wait, self._do_unload, sample_slot) + if not ok: self.sample_can_be_centered = False + + return ok + + def _update_path(self, value): + self.current_path = value + + def _update_running_state(self, value): + """ + Emits signal with new Running State + + @value: New running state + """ + self.path_running = value + self.emit('runningStateChanged', (value, )) + + def _update_powered_state(self, value): + """ + Emits signal with new Powered State + + @value: New powered state + """ + self.emit('powerStateChanged', (value, )) + + def _do_load_xaloc(self, sample=None, use_ht=False): + """ + Loads a sample on the diffractometer. Performs a simple put operation if the + diffractometer is empty, and a sample exchange (unmount of old + mount of new + sample) if a sample is already mounted on the diffractometer. + + If the pick parameters are true + + Overides Cats90 method. + + @sample: sample to load. Either a sample object in case of SPINE/UNIPUCK, or an int in case of hot tool sample + @shifts: mounting point offsets. + @use_ht: mount a sample from hot tool. + """ + if not self._chnPowered.get_value(): + # TODO: implement a wait with timeout method. + self.logger.debug("CATS power is OFF. Trying to switch the power ON...") + self._cmdPowerOn() # try switching power on + gevent.sleep(2) # gevent.sleep(2)?? + + current_tool = self.get_current_tool() + + self.save_detdist_position() + self.logger.debug("Sending supervisor to transfer phase.") + ret,msg = self.send_beamline_to_transfer() + + if ret is False: + self.logger.error( + "Supervisor cmd transfer phase returned an error: %s" % msg) + self._update_state() + raise Exception( + "Supervisor cannot get to transfer phase, error is\n %s\nAborting sample changer operation. Ask LC or floor coordinator to check the supervisor and diff device servers" % msg) + + if not self._chnPowered.get_value(): + self._update_state() + raise Exception( + "CATS power is not enabled. Please interlock the EH and set the CATS switches to the right position before " + "transferring samples." + ) + + self.logger.debug("Selected sample is %s " % sample.get_address() ) + + selected = self.get_selected_sample() + self.logger.debug("Selected sample object is %s " % selected ) + if not use_ht: + if sample is not None: + if sample != selected: + self._do_select(sample) + selected = self.get_selected_sample() + else: + if selected is not None: + sample = selected + else: + raise Exception("No sample selected") + else: + selected = None + + # get sample selection + prev_address = None + if self.get_loaded_sample() != None: + prev_address = self.get_loaded_sample().get_address() + self.logger.debug("Selected sample is %s (prev %s)" % + ( selected.get_address(), prev_address ) + ) + + # some cancel cases + if not use_ht and self.has_loaded_sample() and selected == self.get_loaded_sample(): # sample on diff is the one loaded + self._update_state() + raise Exception("The sample " + + str(self.get_loaded_sample().get_address()) + + " is already loaded") + + if self.cats_sample_on_diffr() == -1 and self.has_loaded_sample(): # no sample on diff, but cats has sample info + self._update_state() + raise Exception( + "Conflicting info between diffractometer and on-magnet detection." + "Consider 'Clear'") + + # obtain mounting offsets from diffr + shifts = self._get_shifts() + + if shifts is None: + xshift, yshift, zshift = ["0", "0", "0"] + else: + xshift, yshift, zshift = map(str, shifts) + + if use_ht: # loading HT sample + # + # Loading HT sample + # + if self.is_loaded_ht() == 1: # has an HT sample mounted + self._do_load_ht( selected, xshift, yshift, zshift ) + else: #TODO no execption?? + self.logger.error("Mixing load/unload dewar vs HT, Unload sample first") + return + else: + # + # Loading non HT sample + # + if self.is_loaded_ht() == 1: # has an HT sample mounted + # first unmount HT TODO: no exception?? + self.logger.warning( + "Mixing load/unload dewar vs HT, unload sample first") + return + else: # either no sample or non HT sample + pick_after_mount, cmd_ok = self._do_load_dewar(selected, xshift, yshift, zshift) + + # At this point, due to the waitsafe, we can be sure that the robot has left RI2 and will not return + # TODO: check if the diff should be prepared or not + collision_occurred = False + if not self._chnCollisionSensorOK.get_value(): + collision_occurred = True + + # A time sleep is needed to get updates on the sample status etc. + #time.sleep(3) + if self.get_current_tool() == TOOL_DOUBLE_GRIPPER and self._chnNBSoakings.get_value() == 0: + self.logger.info("A dry will now be done" ) + + if not cmd_ok: + self.logger.info("Load Command failed on device server") + return False + elif self.auto_prepare_diff and not self.changing_tool and not collision_occurred: + self.logger.info("AUTO_PREPARE_DIFF is on preparing diff now") + allok, msg = self._check_coherence() + if allok: + logging.getLogger('user_level_log').info( 'Sample successfully loaded' ) + self.logger.info("Opening detcover") + HWR.beamline.supervisor.open_detector_cover() + self.logger.info("Restoring detector distance") + self.restore_detdist_position() + else: + # Now recover failed put for double gripper + # : double should be in soak, single should be ?? + #isPathRunning amd cats_idle dont work for tool 5, becuase cats stays in running state after failed put. + #_wait_cats_home followed by immediate abort fails because double tool passed through home on the way to soak + # time.sleep(5) fails because of a possible dry for double + # When doing a dry, CATS passes through home, so a double wait_cats_home is necessary, with a time.sleep of a couple of seconds in between so CATS starts drying + # An alternative is to abort at arriving home, clear memeory and move to soak + if not self._check_incoherent_sample_info()[0] : + msg = "Your sample was NOT loaded! Click OK to recover, please make sure your sample is present in the puck" + else: + msg = "The CATS device indicates there was a problem in unmounting the sample, click ok to recover from a Fix Fail Get" + self.emit("taskFailed", str(msg)) + logging.getLogger('user_level_log').error( + 'There was a problem loading your sample, please wait for the system to recover' + ) + self._wait_cats_home(10) # wait for robot to return from diff + time.sleep( 5 ) # give it time to move, if it goes for a dry, the _chnNBSoakings is set to 0 + #self.logger.debug("self._chnNBSoakings %d " % self._chnNBSoakings.get_value() ) + if self.get_current_tool() == TOOL_DOUBLE_GRIPPER: + if self._chnNBSoakings.get_value() == 0: + self.logger.info("A dry will now be done, waiting %d seconds" % DOUBLE_GRIPPER_DRY_WAIT_TIME) + time.sleep( DOUBLE_GRIPPER_DRY_WAIT_TIME ) # long timeout because of possible dry of the double gripper + else: + #self.logger.info("no dry, waiting 3 seconds" ) + time.sleep( 3 ) # allow the gripper time to move on + if not self._check_incoherent_sample_info()[0] : # this could be replaced by checking return value of _check_coherence, see TODO there + # the behaviour of the SPINE gripper is different when failing put or when failing get. For put, it does a dry, for get, it doesnt + if self.get_current_tool() == TOOL_SPINE: + time.sleep( 16 ) + self.recover_cats_from_failed_put() + else: + self._do_recover_failure() # recover from failed get + msg = "The CATS device indicates there was a problem in unmounting the sample, click ok to recover from a Fix Fail Get" + self._update_state() + #raise Exception( msg ) + + else: + self.logger.info( + "AUTO_PREPARE_DIFF not activated. sample loading done / or changing tool (%s)" % + self.changing_tool + ) + + # Check again the collision sensor in case the robot collided after being in a safe position + if not self._chnCollisionSensorOK.get_value() or collision_occurred: + self._update_state() + msg = "The robot had a collision, call your LC or floor coordinator" + self.emit("taskFailed", str(msg)) + raise Exception ( msg ) + + if pick_after_mount: + load_command = self._cmdPick + lid, sampleno = self.basketsample_to_lidsample( + self.next_pick_sample_location[0], self.next_pick_sample_location[1] + ) + tool = self.tool_for_basket( self.next_pick_sample_location[0] ) + stype = self.get_cassette_type( self.next_pick_sample_location[0] ) + + self.logger.info( + "next_pick_sample_location %s:%s" % + (self.next_pick_sample_location[0], self.next_pick_sample_location[1]) + ) + argin = [ + str(tool), + str(lid), + str(sampleno), + str(stype), + ] + gevent.spawn ( + self._execute_server_task,load_command, argin, waitsafe=True + ) + + self.next_pick_sample_location = [-1,-1] # Dont use pick for the next mounting cycle unless requested + + return cmd_ok + + def _do_load_ht(self, sample, xshift, yshift, zshift): + + tool = self.tool_for_basket(100) # basketno) + + if tool != self.get_current_tool(): + self.logger.warning("Changing tool from %s to %s" % + (self.get_current_tool(), tool)) + self.changing_tool = True + else: + self.changing_tool = False + + argin = ["2", str(sample), "0", "0", xshift, yshift, zshift] + self.logger.warning("Loading HT sample, %s" % str(argin)) + if loaded_ht == 1: # has ht loaded + cmd_ok = self._execute_server_task(self._cmdChainedLoadHT, + argin, waitsafe=True) + else: + cmd_ok = self._execute_server_task(self._cmdLoadHT, argin, waitsafe=False) + + def _do_load_dewar(self, selected, xshift, yshift, zshift): + """ + Load sample from the cold dewar, not the hot tools + Selected is of type sample + """ + + self.logger.debug("_do_chain_load_dewar, selected sample is %s" % selected.get_address() ) + + pick_after_mount = False + cmd_ok = False + + basketno = selected.get_basket_no() + sampleno = selected.get_vial_no() + + lid, sampleno = self.basketsample_to_lidsample(basketno, sampleno) + tool = self.tool_for_basket(basketno) + stype = self.get_cassette_type(basketno) + + if tool != self.get_current_tool(): + self.logger.warning("Changing tool from %s to %s" % + (self.get_current_tool(), tool) + ) + self.changing_tool = True + else: + self.changing_tool = False + + if tool == TOOL_SPINE: + read_barcode = self.read_datamatrix and \ + self._cmdChainedLoadBarcode is not None + self.next_pick_sample_location = [-1,-1] # pick not compatible with SPINE single gripper + else: + if self.read_datamatrix: + self.logger.error("Reading barcode only possible with spine pucks, no barcode will be read") + read_barcode = False + + if self.has_loaded_sample(): # has a loaded but it is not an HT + if self.changing_tool: + self._update_state() + raise Exception( + "This operation requires a tool change. You should unload" + "sample first") + pick_after_mount, cmd_ok = self._do_chain_load_dewar( + selected, + self.next_pick_sample_location, + tool, + read_barcode, + xshift, + yshift, + zshift + ) + + else: # no loaded sample + cmd_ok = self._do_nochain_load_dewar(selected, tool, read_barcode, xshift, yshift, zshift) + pick_after_mount = ( not -1 in self.next_pick_sample_location ) + + return pick_after_mount, cmd_ok + + def _do_chain_load_dewar(self, selected, pick_sample_location, tool, read_barcode, xshift, yshift, zshift ): + """ + do an unload followd by a load. If requested, followed by a pick + pick_sample_location is an array, like location + Return pick_required true if the pick needs a separate, consecutive operation + """ + + self.logger.debug("_do_chain_load_dewar, pick_sample_location %s" % str(pick_sample_location) ) + + pick_required = False + + basketno = selected.get_basket_no() + sampleno = selected.get_vial_no() + + lid, sampleno = self.basketsample_to_lidsample(basketno, sampleno) + tool = self.tool_for_basket(basketno) + stype = self.get_cassette_type(basketno) + + # First check if there is a mount request where the sample on tool is not the selected sample + if self.sample_lid_on_tool != -1 and self.sample_num_on_tool != -1: + if self.sample_lid_on_tool != lid or self.sample_num_on_tool != sampleno: + # there is a sample on the tool and it does not match the requested pick sample. + # Unload required, which will return the sample to the dewar + # The operation should be waited for, so waitsafe = False + argin = [str(tool), "0", xshift, yshift, zshift] + cmd_ok = self._execute_server_task( self._cmdUnload, argin, waitsafe=False ) + + if self.sample_lid_on_tool == -1 and self.sample_num_on_tool == -1: + self.logger.debug("_do_chain_load_dewar, no sample on tool") + # no sample on tool, just load the requested sample using a standard chain load + # NOTE, a subsequent pick should still be done if pick_sample_location is not None! + if self.has_loaded_sample(): # no picked sample, but sample on diff, just exchange + pick_required = ( not -1 in pick_sample_location ) + self.logger.debug("_do_chain_load_dewar, sample on diff") + if read_barcode: + chained_load_command = self._cmdChainedLoadBarcode + self.logger.warning( + "Chained load sample using barcode requested" ) + else: + chained_load_command = self._cmdChainedLoad + argin = [ + str(tool), + str(lid), + str(sampleno), + str(stype), + "0", + xshift, + yshift, + zshift] + else: # no picked sample, no sample on diff, we got here because the picked sample was not the one requested, so do load + if read_barcode: + chained_load_command = self._cmdLoadBarcode + self.logger.warning( + "Load sample using barcode requested" ) + else: + chained_load_command = self._cmdLoad + argin = [ + str(tool), + str(lid), + str(sampleno), + str(stype), + "0", + xshift, + yshift, + zshift] + elif self.sample_lid_on_tool == lid or self.sample_num_on_tool == sampleno: + # There is a sample on the tool, and it coincides with the requested sample. + # pick is included in the sequence, the robot will pick the smaple in the arguments after loading the requested sample + if not -1 in pick_sample_location: + # A pick is requested, so do a chainloadpick and pass as sample parameters the pick sample + # This is crazy fast, so a sleep is introduced to give the diff and detector time to move + #self.logger.debug("Doing sleep before getputpick") + gevent.sleep(0.5) + #self.logger.debug("Doing getputpick") + chained_load_command = self._cmdChainedLoadPick + lid, sampleno = self.basketsample_to_lidsample( + pick_sample_location[0], pick_sample_location[1] + ) + argin = [ + str(tool), + str(lid), + str(sampleno), + str(stype), + "0", + xshift, + yshift, + zshift] + else: + # no pick requested, simply pass the selected sample loaded on the tool as sample arguments to a normal chain load + # no subsequent pick required + chained_load_command = self._cmdChainedLoad + argin = [ + str(tool), + str(self.sample_lid_on_tool), + str(self.sample_num_on_tool), + str(stype), + "0", + xshift, + yshift, + zshift] + + self.logger.info("Doing a chained load using command %s" % str( self._cmdChainedLoad.name() ) ) + self.logger.warning("Arguments for cats: %s" % argin) + + cmd_ok = self._execute_server_task( + chained_load_command, argin, waitsafe=True) + + return pick_required, cmd_ok + + def _do_nochain_load_dewar(self, selected, tool, read_barcode, xshift, yshift, zshift ): + """ + Do a simple load, no sample to unload. If a pick is required, this should be done in a subsequent operation + """ + + basketno = selected.get_basket_no() + sampleno = selected.get_vial_no() + + lid, sampleno = self.basketsample_to_lidsample(basketno, sampleno) + tool = self.tool_for_basket(basketno) + stype = self.get_cassette_type(basketno) + + # in case that there is a sample on the tool, the sample info in the arguments is ignored by CATS. + # in case that there is no sample on the tool, the selected sample is mounted. + load_command = self._cmdLoad + + if read_barcode: + self.logger.info( "Load sample and read barcode" ) + load_command = self._cmdLoadBarcode + + argin = [ + str(tool), + str(lid), + str(sampleno), + str(stype), + "0", + xshift, + yshift, + zshift] + + # No need to wait for the robot to finish + cmd_ok = self._execute_server_task( + load_command, argin, waitsafe=True) + + return cmd_ok + + def _wait_device_safe(self,timeout=10): + """ + Waits until the samle changer HO is safe, aka not returning to diff. + + :returns: None + :rtype: None + """ + with gevent.Timeout(timeout, Exception("Timeout waiting for device ready")): + while not self.path_safe(): + gevent.sleep(0.01) + + def _do_unload(self, sample_slot=None): + """ + Unloads a sample from the diffractometer. + Overides Cats90 method. + + @sample_slot: + """ + self.logger.debug("checking power") + if not self._chnPowered.get_value(): + try: + self._cmdPowerOn() # try switching power on + except Exception as e: + self._update_state() + raise Exception(e) + + #TODO: wait for cats poweron + + ret, msg = self.send_beamline_to_transfer() + + if ret is False: + self.logger.error( + "Supervisor cmd transfer phase returned an error: %s" % msg) + raise Exception( + "Supervisor cannot get to transfer phase, error is\n %s\nAborting sample changer operation. Ask LC or floor coordinator to check the supervisor and diff device servers" % msg) + + shifts = self._get_shifts() + + if sample_slot is not None: + self._do_select(sample_slot) + + loaded_ht = self.is_loaded_ht() + + if shifts is None: + xshift, yshift, zshift = ["0", "0", "0"] + else: + xshift, yshift, zshift = map(str, shifts) + + loaded_lid = self._chnLidLoadedSample.get_value() + loaded_num = self._chnNumLoadedSample.get_value() + + if loaded_lid == -1: + self.logger.warning("Unload sample, no mounted sample detected") + return False + + loaded_basket, loaded_sample = self.lidsample_to_basketsample( + loaded_lid, loaded_num) + + tool = self.tool_for_basket(loaded_basket) + + argin = [str(tool), "0", xshift, yshift, zshift] + + self.logger.warning("Unload sample, sending to cats: %s" % + argin) + if loaded_ht == 1: + cmd_ret = self._execute_server_task(self._cmdUnloadHT, argin, waitsafe=True) + else: + cmd_ret = self._execute_server_task(self._cmdUnload, argin, waitsafe=True) + + # At this point, due to the waitsafe, we can be sure that the robot has left RI2 and will not return + # A time sleep is needed to get updates on the sample status etc. + #gevent.sleep(3) + + + allok = self._check_coherence()[0] + if not allok: + HWR.beamline.supervisor.wait_ready() + if not self.has_loaded_sample() and self.cats_sample_on_diffr(): + msg = "The CATS device indicates there was a problem in unmounting the sample, click on Fix Fail Get" + self._update_state() + raise Exception( msg ) + + return True + + def sample_lid_on_tool_changed(self, value): + self.sample_lid_on_tool = value + + def sample_num_on_tool_changed(self, value): + self.sample_num_on_tool = value + + def set_next_pick_sample(self, pick_sample_location): + self.next_pick_sample_location = pick_sample_location + if self.next_pick_sample_location == None: self.next_pick_sample_location = [-1,-1] + + def _do_abort(self): + """ + Aborts a running trajectory on the sample changer. + + :returns: None + :rtype: None + """ + if self.super_abort_cmd is not None: + self.super_abort_cmd() # stops super + self._cmdAbort() + self._update_state() # remove software flags like Loading.. reflects current hardware state + + def _check_coherence(self): + + sampinfobool, sampinfomessage = self._check_incoherent_sample_info() + unknownsampbool, unknownsampmessage = self._check_unknown_sample_presence() + msg = sampinfomessage + unknownsampmessage + return ( sampinfobool and unknownsampbool ), msg + + def _check_unknown_sample_presence(self): + + detected = self._chnSampleIsDetected.get_value() + loaded_lid = self._chnLidLoadedSample.get_value() + loaded_num = self._chnNumLoadedSample.get_value() + #self.logger.debug("detected %s, type detected %s, loaded_lid %d, loaded_num %d, loaded_num type %s" % ( str(detected), type(detected), loaded_lid, loaded_num, type(loaded_num) ) ) + #self.logger.debug("-1 in [loaded_lid, loaded_num] %s, detected %s" % ( -1 in [loaded_lid, loaded_num], detected ) ) + #self.logger.debug("-1 in [loaded_lid, loaded_num] and detected: %s" % ( -1 in [loaded_lid, loaded_num] and detected ) ) + + + if -1 in [loaded_lid, loaded_num] and detected: + return False, "Sample detected on Diffract. but there is no info about it" + + return True, "" + + def _check_incoherent_sample_info(self): + """ + Check for sample info in CATS but no physically mounted sample + (Fix failed PUT) + Returns False in case of incoherence, True if all is ok + """ + #self.logger.debug('self._chnSampleIsDetected %s' % self._chnSampleIsDetected.get_value() ) + detected = self._chnSampleIsDetected.get_value() + loaded_lid = self._chnLidLoadedSample.get_value() + loaded_num = self._chnNumLoadedSample.get_value() + #self.logger.debug("detected %s, loaded_lid %d, loaded_num %d" % ( str(detected), loaded_lid, loaded_num ) ) + + if not detected and not ( -1 in [loaded_lid, loaded_num] ): + return False, "There is info about a sample in CATS but it is not detected on the diffract." + + return True, "" + + def _update_loaded_sample(self, sample_num=None, lid=None): + """ + Reads the currently mounted sample basket and pin indices from the CATS Tango DS, + translates the lid/sample notation into the basket/sample notation and marks the + respective sample as loaded. + + :returns: None + :rtype: None + """ + if not self._chnSampleIsDetected.get_value(): + Cats90._update_loaded_sample(self, -1, -1) + else: + Cats90._update_loaded_sample(self, sample_num, lid) + + def _get_shifts(self): + """ + Get the mounting position from the Diffractometer DS. + + @return: 3-tuple + """ + if self.shifts_channel is not None: + shifts = self.shifts_channel.get_value() + else: + shifts = None + self.logger.debug('Shifts of the diffractometer position: %s' % str(shifts) ) + return shifts + + # TODO: fix return type + def is_ht_sample(self, address): + """ + Returns is sample address belongs to hot tool basket. + + @address: sample address + @return: int or boolean + """ + try: basket, sample = address.split(":") # address is string (when loading from tree) + except: basket, sample = address # address is tuple (when loading from sample changer tab) + + try: + if int(basket) >= 100: + return int(sample) + else: + return False + except Exception as e: + self._update_state() + self.logger.debug("Cannot identify sample in hot tool") + return False + + def tool_for_basket(self, basketno): + """ + Returns the tool corresponding to the basket. + + @basketno: basket number + @return: int + """ + if basketno == 100: + return TOOL_SPINE + + return Cats90.tool_for_basket(self, basketno) + + def is_loaded_ht(self): + """ + 1 : has loaded ht + 0 : nothing loaded + -1 : loaded but not ht + """ + sample_lid = self._chnLidLoadedSample.get_value() + + if self.has_loaded_sample(): + if sample_lid == 100: + return 1 + else: + return -1 + else: + return 0 + + def _do_reset(self): + """ + Called when user pushes "Fix fail PUT" button + Overrides the _doReset in CatsMaint, adding checks whether calling this method is justified + """ + self.recover_cats_from_failed_put() + + def recover_cats_blocked_in_RI2(self): + self._cmdCATSRecovery(wait = True) + + def recover_cats_from_failed_put(self): + """ + Deletes sample info on diff, but should retain info of samples on tools, eg when doing picks + TODO: tool2 commands are not working, eg SampleNumberInTool2 + """ + self.logger.debug("XalocCats recovering from failed put. Failed put is %s" % str( self._check_incoherent_sample_info() ) ) + + if not self._check_incoherent_sample_info()[0]: + self._cmdAbort() + savelidsamptool = self._chnLidSampleOnTool.get_value() + savenumsamptool = self._chnNumSampleOnTool.get_value() + #savelidsamptool2 = self._chnLidSampleOnTool2() # Not implemented yet + #savenumsamptool2 = self._chnNumSampleOnTool2() # Not implemented yet + self._cmdClearMemory() + if not -1 in [savelidsamptool, savenumsamptool ]: + basketno, bsampno = self.lidsample_to_basketsample( + savelidsamptool,savenumsamptool + ) + argin = [ str(savelidsamptool), + str(savenumsamptool), + str( self.get_cassette_type( basketno ) ) + ] + self.logger.debug("XalocCats recover from failed put. Sending to robot %s" % argin ) + cmdok = self._execute_server_task( self._cmdSetTool, argin ) + #if not -1 in [savelidsamptool2, savenumsamptool2 ]: + # basketno, bsampno = self.lidsample_to_basketsample(savelidsamptool2,savenumsamptool2) # Not implemented yet + # argin = [ str(savelidsamptool2), str(savenumsamptool2), str(self.get_cassette_type(basketno)) ] + # self._execute_server_task( self._cmdSetTool2, argin ) + else: raise Exception("The conditions of the beamline do not fit a failed put situation, " + "Fixed failed PUT is not justified. Find another solution.") + + def _do_recover_failure(self): + """ + Called when user pushes "Fix fail GET" button + Overrides the _do_recover_failure in CatsMaint, adding checks whether calling this method is justified + """ + self.logger.debug("XalocCats recovering from failed get") + self.recover_cats_from_failed_get() + + def recover_cats_from_failed_get(self): + """ + Deletes sample info on diff, but should retain info of samples on tools, eg when doing picks + TODO: tool2 commands are not working, eg SampleNumberInTool2 + """ + if not self._check_unknown_sample_presence()[0]: + self._cmdRecoverFailure() + else: raise Exception("The conditions of the beamline do not fit a failed get situation, " + "Fixed failed GET is not justified. Find another solution.") + + + def lidsample_to_basketsample(self, lid, num): + if self.is_isara(): + return lid, num + else: + if lid == 100: + return lid, num + + lid_base = (lid - 1) * self.baskets_per_lid # nb of first basket in lid + basket_type = self.basket_types[lid_base] + + if basket_type == BASKET_UNIPUCK: + samples_per_basket = SAMPLES_UNIPUCK + elif basket_type == BASKET_SPINE: + samples_per_basket = SAMPLES_SPINE + else: + samples_per_basket = self.samples_per_basket + + lid_offset = ((num - 1) / samples_per_basket) + 1 + sample_pos = ((num - 1) % samples_per_basket) + 1 + basket = lid_base + lid_offset + return basket, sample_pos + + def basketsample_to_lidsample(self, basket, num): + if self.is_isara(): + return basket, num + else: + if basket == 100: + return basket, num + + lid = ((basket - 1) / self.baskets_per_lid) + 1 + + basket_type = self.basket_types[basket - 1] + if basket_type == BASKET_UNIPUCK: + samples_per_basket = SAMPLES_UNIPUCK + elif basket_type == BASKET_SPINE: + samples_per_basket = SAMPLES_SPINE + else: + samples_per_basket = self.samples_per_basket + + sample = (((basket - 1) % self.baskets_per_lid) * samples_per_basket) + num + return lid, sample + + + + def _execute_server_task(self, method, *args, **kwargs): + """ + Executes a task on the CATS Tango device server + Xaloc: added collision detection while waiting for safe + + :returns: None + :rtype: None + """ + #logging.getLogger("HWR").debug("XalocCats. executing method %s " % str( method.name() )) + self._wait_device_ready(timeout = 60) #TODO adjust time out according to times needed for dries etc? + try: + task_id = method(*args) + except: + import traceback + self.logger.debug("XalocCats exception while executing server task") + self.logger.debug(traceback.format_exc()) + task_id = None + self._update_state() + raise Exception("The command could not be sent to the robot, check its state.") + #TODO: why not return with an Exception here to inform there is a problem with the CATS? + + waitsafe = kwargs.get('waitsafe',False) + waitfinished = kwargs.get('waitfinished',False) + logging.getLogger("HWR").debug("XalocCats. executing method %s / task_id %s / waiting only for safe status is %s" % (str(method), task_id, waitsafe)) + + # What does the first part of the if do? It's not resetting anything... + ret=None + if task_id is None: #Reset + while self._is_device_busy(): + gevent.sleep(0.1) + return False + else: + # introduced wait because it takes some time before the attribute PathRunning is set + # after launching a transfer. This is only necessary if the trajectory is not safe + #if task_id not in ['pick']: + #self.logger.debug("Going to sleep for 6 seconds, task_id is %s" % task_id) + #gevent.sleep(4.0) + self.logger.debug("Waiting for the HO to be busy") + while not self._is_device_busy(): + gevent.sleep(0.1) + self.logger.debug("Starting error detection loop") + while self._is_device_busy(): + if waitsafe: + #TODO: when a sample is loaded but not present, detect this... + if self.get_loaded_sample() == self.get_selected_sample() and not self.cats_ri2: + logging.getLogger("HWR").debug("Server execution polling finished as requested sample is mounted and cats left diff ") + break + #if self.path_safe(): # this doesnt work for getputpick, pathsafe is not handled well for this trajectory in the cats DS + #logging.getLogger("HWR").debug("Server execution polling finished as path is safe") + #break + #if self.get_loaded_sample() == self.get_selected_sample(): + #logging.getLogger("HWR").debug("Cats90. server execution polling finished as loaded sample is the requested one") + #gevent.sleep(1) # adjust according to need: this is the time needed for the robot to retreat from the diff + #break + elif not self.path_running(): + logging.getLogger("HWR").debug("server execution polling finished as path is not running") + break + if not self._check_incoherent_sample_info()[0] and not self.cats_ri2: + logging.getLogger("HWR").debug("server execution polling finished as cats thinks there is a sample on the diff, but there is not") + break + if not self._chnCollisionSensorOK.get_value(): + # Should the exception be raised here?? It is also done in _do_load + self._update_state() + logging.getLogger("HWR").debug("Cats90. server execution polling finished as path is safe") + raise Exception ("The robot had a collision, call your LC or floor coordinator") + elif not self.cats_powered and self.cats_ri2: + # CATS is blocked in front of diff + logging.getLogger("HWR").debug("Cats90. Robot blocked in front of diff, attempting a recovery") + self.recover_cats_blocked_in_RI2() + gevent.sleep(2.0) + # in case nothing is happening. The check for RI1 is because there is a transient loss of sample info when changing samples + #if not self._check_unknown_sample_presence()[0] and not self._chnIsCatsRI1.get_value(): + #break + gevent.sleep(0.3) + ret = True + logging.getLogger("HWR").debug("XalocCats. return value from method _execute_server_task is %s" % str( ret ) ) + return ret + + def assert_can_execute_task(self): + """ + Raises: + (Exeption): If sample changer cannot execute a task + """ + if not self.is_ready(): + error_msg = "" + state_str = SampleChangerState.tostring(self.state) + if state_str == "Loading" or state_str == "Unloading": + error_msg = "The robot is busy, please wait till the robot finishes and try again." + elif state_str == "Unknown": + error_msg = "The robot is busy, you may need to use the sample changer details tab to unload the sample" + elif state_str == "Moving": + error_msg = "The robot is doing a %s trajectory, please wait and try again" % self.current_path + else: + error_msg = "Cannot execute task, robot is not ready" + raise Exception( + error_msg + " ( state is " + + SampleChangerState.tostring(self.state) + + ")" + ) + +def test_hwo(hwo): + hwo._updateCatsContents() + print("Is path running? ", hwo.is_path_running()) + print("Loading shifts: ", hwo._get_shifts()) + print("Sample on diffr : ", hwo.cats_sample_on_diffr()) + print("Baskets : ", hwo.basket_presence) + print("Baskets : ", hwo.get_basket_list()) + if hwo.has_loaded_sample(): + print("Loaded is: ", hwo.get_loaded_sample().getCoords()) + print("Is mounted sample: ", hwo.is_mounted_sample((1, 1))) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocCatsMaint.py b/mxcubecore/HardwareObjects/ALBA/XalocCatsMaint.py new file mode 100755 index 0000000000..88068c3e99 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocCatsMaint.py @@ -0,0 +1,124 @@ +# +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] XalocCatsMaint + +[Description] +HwObj used to operate the CATS sample changer via Tango in maintenance mode + +[Signals] +- None +""" + +#from __future__ import print_function +import logging +from mxcubecore.HardwareObjects.CatsMaint import CatsMaint + +__credits__ = ["ALBA Synchrotron"] +__version__ = "3" +__category__ = "General" + + +class XalocCatsMaint(CatsMaint): + + def __init__(self, *args, **kwargs): + CatsMaint.__init__(self, *args, **kwargs) + self.logger = logging.getLogger("HWR.XalocCatsMaint") + self.chan_shifts = None + self.chan_at_home = None + self.cmd_super_abort = None + + def init(self): + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + CatsMaint.init(self) + + # channel to ask diffractometer for mounting position + self.chan_shifts = self.get_channel_object("shifts") + self.chan_at_home = self.get_channel_object("_chnAtHome") + self.cmd_super_abort = self.get_command_object("super_abort") + + # To get acces to recovery functions + self.Cats90 = self.get_object_by_role("cats90") + + def _do_abort(self): + if self.cmd_super_abort is not None: + self.cmd_super_abort() + self._cmdAbort() + + def _do_reset_memory(self): + """ + Reset CATS memory. + """ + # Check do_PRO6_RAH first + if self.chan_at_home.get_value() is True: + CatsMaint._do_reset_memory(self) + + def _check_unknown_sample_presence(self): + self.Cats90._check_unknown_sample_presence() + + def _check_incoherent_sample_info(self): + """ + Check for sample info in CATS but no physically mounted sample + (Fix failed PUT) + Returns False in case of incoherence, True if all is ok + """ + self.Cats90._check_incoherent_sample_info() + + def _do_recover_failure(self): + """ + Failed get + """ + self.Cats90._do_recover_failure() + + def _do_reset(self): + """ + Reset CATS system after failed put + Deletes sample info on diff, but should retain info of samples on tools, eg when doing picks + TODO: tool2 commands are not working, eg SampleNumberInTool2 + """ + self.Cats90._do_reset() + + def _get_shifts(self): + """ + Get the mounting position from the Diffractometer DS. + + @return: 3-tuple + """ + if self.chan_shifts is not None: + shifts = self.chan_shifts.get_value() + else: + shifts = None + return shifts + + def re_emit_signals(self): + self.emit("runningStateChanged", (self._running,)) + self.emit("powerStateChanged", (self._powered,)) + self.emit("toolStateChanged", (self._toolopen,)) + self.emit("messageChanged", (self._message,)) + self.emit("barcodeChanged", (self._barcode,)) + self.emit("lid1StateChanged", (self._lid1state,)) + self.emit("lid2StateChanged", (self._lid2state,)) + self.emit("lid3StateChanged", (self._lid3state,)) + self.emit("regulationStateChanged", (self._regulating,)) + + + +def test_hwo(hwo): + print(hwo._get_shifts()) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocCluster.py b/mxcubecore/HardwareObjects/ALBA/XalocCluster.py new file mode 100755 index 0000000000..b26d4150f8 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocCluster.py @@ -0,0 +1,178 @@ +# +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . +# +# +# Job submission to the ALBA cluster is managed by the slurm_client +# The USER / SCRATCH keyword sets if the files are copied first to local disk on the cluster (SCRATCH) +# or if the file I/O during the characterization job is done directly on the directorires of the user (USER) +# + + +""" +[Name] XalocCluster + +[Description] +HwObj providing access to the ALBA cluster. + +[Signals] +- None +""" + +from __future__ import print_function + +import os +import time +import logging + +from mxcubecore.BaseHardwareObjects import HardwareObject +from slurm_client import EDNAJob, Manager, Account +from slurm_client.utils import create_edna_yml + + +__credits__ = ["ALBA Synchrotron"] +__version__ = "2.3" +__category__ = "General" +__author__ = "Jordi Andreu" + + +class XalocCluster(HardwareObject): + def __init__(self, name): + HardwareObject.__init__(self, name) + self.logger = logging.getLogger("HWR.XalocCluster") + self.account = None + self.manager = None + self.use_env_scripts_root = True + self._scripts_root = None + self.pipelines = {} + self._jobs = None + + def init(self): + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + user = self.get_property("user") + cla = self.get_property("cla") + + self._scripts_root = self.get_property("pipelines_scripts_root") + + if self._scripts_root: + self.use_env_scripts_root = False + + for name in ['strategy', 'ednaproc', 'autoproc', 'xia2']: + if self.get_property("{}_pipeline".format(name)): + _pipeline = eval(self.get_property("{}_pipeline".format(name))) + if _pipeline: + self.pipelines[name] = _pipeline + self.logger.debug("Adding {0} pipeline {1}".format(name, _pipeline)) + + self.account = Account(user=user, cla=cla, scripts_root=self._scripts_root) + self.manager = Manager([self.account]) + self.logger.debug("cluster user: {0}".format(self.account.user)) + self.logger.debug("cluster CLA: {0}".format(self.account.cla)) + try: self.logger.debug("scripts root: {0}".format( self.account.scripts_root ) ) + except: pass + + def run(self, job): + self.manager.submit(job) + + def wait_done(self, job): + state = self.manager.get_job_state(job) + self.logger.debug("Job state is %s" % state) + + while state in ["RUNNING", "PENDING"]: + self.logger.debug("Job / is %s" % state) + time.sleep(0.5) + state = self.manager.get_job_state(job) + + self.logger.debug(" job finished with state: \"%s\"" % state) + return state + + def create_strategy_job(self, collect_id, input_file, output_dir): + + plugin_name = self.pipelines['strategy']['plugin'] + slurm_script = os.path.join(self._scripts_root, + self.pipelines['strategy']['script']) + + _yml_file = create_edna_yml(str(collect_id), + plugin_name, + input_file, + slurm_script, + workarea='SCRATCH', + benchmark=False, + dest=output_dir, + use_scripts_root=self.use_env_scripts_root, + xds=None, + configdef=None) + return EDNAJob(_yml_file) + + def create_autoproc_job(self, collect_id, input_file, output_dir): + + plugin_name = self.pipelines['autoproc']['plugin'] + slurm_script = os.path.join(self._scripts_root, + self.pipelines['autoproc']['script']) + configdef = os.path.join(self._scripts_root, + self.pipelines['autoproc']['configdef']) + + self.logger.debug("configDef is %s" % configdef) + + _yml_file = create_edna_yml(str(collect_id), + plugin_name, + input_file, + slurm_script, + workarea='SCRATCH', + benchmark=False, + dest=output_dir, + use_scripts_root=self.use_env_scripts_root, + xds=None, + configdef=configdef) + return EDNAJob(_yml_file) + + def create_xia2_job(self, collect_id, input_file, output_dir): + + plugin_name = self.pipelines['xia2']['plugin'] + slurm_script = os.path.join(self._scripts_root, + self.pipelines['xia2']['script']) + + _yml_file = create_edna_yml(str(collect_id), + plugin_name, + input_file, + slurm_script, + workarea='SCRATCH', + benchmark=False, + dest=output_dir, + use_scripts_root=self.use_env_scripts_root, + xds=None, + configdef=None) + return EDNAJob(_yml_file) + + def create_ednaproc_job(self, collect_id, input_file, output_dir): + + plugin_name = self.pipelines['ednaproc']['plugin'] + slurm_script = os.path.join(self._scripts_root, + self.pipelines['ednaproc']['script']) + + _yml_file = create_edna_yml(str(collect_id), + plugin_name, + input_file, + slurm_script, + workarea='SCRATCH', + benchmark=False, + dest=output_dir, + use_scripts_root=self.use_env_scripts_root, + xds=None, + configdef=None) + return EDNAJob(_yml_file) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocCollect.py b/mxcubecore/HardwareObjects/ALBA/XalocCollect.py new file mode 100755 index 0000000000..f5054c5f23 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocCollect.py @@ -0,0 +1,2347 @@ +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] XalocCollect + +[Description] +Specific implementation of the collection methods for ALBA synchrotron. +Basic Flow: + do_collect in AbstractCollect: + data_collection_hook in XalocCollect + prepare_acquisition in XalocCollect + detector_hwobj.prepare_acquisition + prepare_collection in XalocCollect <-- Repeated for each test image in case of characterization + detector_hwobj.prepare_collection <-- Repeated for each test image in case of characterization + collect_images + wait_collection_done + collection_finished (AbstractCollect) if collection works + collection_failed if there is a problem + data_collection_cleanup is always called from do_collect (supersedes AbstractCollect method with same name) + + IMPORTANT: the stop button in mxcube throughs an exception in the queue, so there is no need to throw exceptions in Collect + + +TODO: dc has a parameter run_processing_after which is not used in collection_finished + should we reimplement collection_finished to add an if statement to decide to run? + If we do, run_online_processing_cbox should be selected by default in the processing_widget + +There are currently three routines used for when a collection fails + data_collection_failed in XalocCollect + calls stop_collect (is this explicit call necessary?) + collection_failed in AbstractCollect is called from do_collect in case of failure + +In case the user aborts data collection, stopCollect is called, then stop_collect then data_collection_cleanup + In that case, is post processing prevented? + +[Signals] +- progressInit +- collectConnected +- collectStarted +- collectReady +- progressStop +- collectOscillationFailed + +Implementation of Sardana collects uses Macros, as defined in ./HardwareRepository/Command/Sardana.py +We need to investigate how to stop Macros +""" + +# RB 2020102: data collection sweeps to be done through a Sardana Macro + +from __future__ import print_function + +import os +import sys +import time +import gevent +import logging +import math +import glob + +from mxcubecore.TaskUtils import task +from mxcubecore.HardwareObjects.abstract.AbstractCollect import AbstractCollect +from taurus.core.tango.enums import DevState +#from xaloc.resolution import get_dettaby, get_resolution +from mxcubecore import HardwareRepository as HWR +from datetime import datetime + +__credits__ = ["ALBA Synchrotron"] +__version__ = "3" +__category__ = "General" + + +class XalocCollect(AbstractCollect): + """Main data collection class. Inherited from AbstractMulticollect class + Collection is done by setting collection parameters and + executing collect command + """ + + def __init__(self, name): + AbstractCollect.__init__(self, name) + self.logger = logging.getLogger("HWR.XalocCollect") + self.user_logger = logging.getLogger("user_level_log") + self.supervisor_hwobj = None + self.fastshut_hwobj = None + self.slowshut_hwobj = None + self.photonshut_hwobj = None + self.frontend_hwobj = None + self.diffractometer_hwobj = None + self.omega_hwobj = None + self.lims_client_hwobj = None + self.image_tracking_hwobj = None + + self.machine_info_hwobj = None + self.energy_hwobj = None + self.resolution_hwobj = None + self.transmission_hwobj = None + self.detector_hwobj = None + self.beam_info_hwobj = None + #self.graphics_manager_hwobj = None + self.autoprocessing_hwobj = None + self.flux_hwobj = None + self.aborted_by_user = None + + self.cmd_ni_conf = None + self.cmd_ni_unconf = None + + self.set_pilatus_saving_pattern = None + self.ascanct = None + self.meshct = None + self.senv = None + self.mxcube_sardanascan_running = None + + self.chan_kappa_pos = None + self.chan_phi_pos = None + + self.chan_undulator_gap = None + + self.scan_motors_hwobj = {} + self.xaloc_motor_names_dict = {} + + self._error_msg = "" + self.osc_id = None + self._collecting = None + + self.omega_hwobj = None + + self.use_sardana_scan = None + self.scan_start_positions = {} + self.scan_end_positions = {} + self.scan_velocities = {} + self.scan_init_velocities = {} + self.scan_init_positions = {} + self.scan_motors_hwobj = {} + self.scan_move_motor_names = [] + self.scan_all_motor_names = [] + + self.mesh_mxcube_horizontal_motor_name = None + self.mesh_mxcube_vertical_motor_name = None + self.mesh_fast_index = None + self.mesh_slow_index = None + self.mesh_horizontal_index = None + self.mesh_vertical_index = None + self.mesh_sshaped_bool = None # True: up and down scans, False: only up scans + self.mesh_fast_motor_max_velocity = None + + #self.helical_positions = None + #self.saved_omega_velocity = None + + self.bypass_shutters = False + self.rescorner = None + + self.symbolic_link_image_destination = None + + def init(self): + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + self.ready_event = gevent.event.Event() + + self.supervisor_hwobj = self.get_object_by_role("supervisor") + self.fastshut_hwobj = self.get_object_by_role("fast_shutter") + self.slowshut_hwobj = self.get_object_by_role("slow_shutter") + self.photonshut_hwobj = self.get_object_by_role("photon_shutter") + self.frontend_hwobj = self.get_object_by_role("frontend") + self.diffractometer_hwobj = self.get_object_by_role("diffractometer") + self.omega_hwobj = self.get_object_by_role("omega") + self.lims_client_hwobj = self.get_object_by_role("lims_client") + self.image_tracking_hwobj = self.get_object_by_role("image_tracking") + self.machine_info_hwobj = self.get_object_by_role("machine_info") + self.energy_hwobj = self.get_object_by_role("energy") + self.resolution_hwobj = self.get_object_by_role("resolution") + self.transmission_hwobj = self.get_object_by_role("transmission") + self.detector_hwobj = self.get_object_by_role("detector") + self.beam_info_hwobj = self.get_object_by_role("beam_info") + #self.graphics_manager_hwobj = self.get_object_by_role("graphics_manager") + self.autoprocessing_hwobj = self.get_object_by_role("offline_processing") + self.flux_hwobj = self.get_object_by_role("flux") + self.aborted_by_user = False + + # + # + # START of 20210218: Lines only necessary for ni660 collects, remove when switching to pure meshct/ascanct scans + self.cmd_ni_conf = self.get_command_object("ni_configure") + self.cmd_ni_unconf = self.get_command_object("ni_unconfigure") + # END of lines for ni660 scans + # + # + + self.set_pilatus_saving_pattern = self.get_command_object("set_pilatus_saving_pattern") + self.ascanct = self.get_command_object("ascanct") + self.meshct = self.get_command_object("meshct") + self.senv = self.get_command_object("senv") + self.mxcube_sardanascan_running = False # Is set equal to the macro running whem mecessary + + + self.chan_kappa_pos = self.get_channel_object("kappapos") + self.chan_phi_pos = self.get_channel_object("phipos") + + self.xaloc_motor_names_dict = {'phi': 'omega', + 'phiy' : 'omegax', + 'phiz': 'omegaz', + 'kappa': 'kappa', + 'kappaphi': 'phi', + 'sampx': 'centx', + 'sampy': 'centy'} + + self.use_sardana_scan = self.get_property('use_sardana_scan') + #self.scan_all_motor_names = ['phiy', 'phiz', 'sampx', 'sampy', 'kappa', 'kappa_phi'] + self.scan_all_motor_names = ['phiy', 'phiz', 'sampx', 'sampy'] + #TODO get rid of hardcoded max and minvelocity numbers + for scan_motor in self.scan_all_motor_names: + self.scan_motors_hwobj[scan_motor] = self.get_object_by_role(scan_motor) + + self.mesh_mxcube_horizontal_motor_name = 'phiy' # omegax + self.mesh_mxcube_vertical_motor_name = 'phiz' # omegaz + self.mesh_horizontal_index = 0 + self.mesh_vertical_index = 1 + self.mesh_fast_motor_max_velocity = 1.5 # mm/sec. Physically the motor should be fine up to 3.0 mm/sec + + self.mesh_sshaped_bool = self.get_property('mesh_sshape') # False: only up scans + + self.symbolic_link_image_destination = self.get_property('symbolic_link_image_destination') + #self.chan_undulator_gap = self.get_channel_object("chanUndulatorGap") + + self.scan_motors_hwobj = {} + #TODO 20200921 kappa_phi is broken + #self.scan_all_motor_names = ['phiy', 'phiz', 'sampx', 'sampy', 'kappa', 'kappa_phi'] + self.scan_all_motor_names = ['phiy', 'phiz', 'sampx', 'sampy'] + #TODO get rid of hardcoded max and minvelocity numbers + self.scan_motors_min_velocity = {'phiy': 6E-6, 'phiz': 1.3E-4, 'sampx': 7E-6, 'sampy': 7E-6, 'kappa': 4, 'kappaphi': 7} # see XALOC elog 925 + self.scan_motors_max_velocity = {'phiy': 3.0, 'phiz': 0.5, 'sampx': 0.15, 'sampy': 0.15, 'kappa': 17, 'kappaphi': 70} + for scan_motor in self.scan_all_motor_names: + self.scan_motors_hwobj[scan_motor] = self.get_object_by_role(scan_motor) + + undulators = [] + try: + for undulator in self["undulators"]: + undulators.append(undulator) + except BaseException: + pass + + self.exp_type_dict = {'Mesh': 'raster', + 'Helical': 'Helical'} + + self.omega_init_pos = self.omega_hwobj.get_value() + self.omega_init_vel = 60 + + + det_px, det_py = self.detector_hwobj.get_pixel_size() + + self.set_beamline_configuration( + synchrotron_name="ALBA", + directory_prefix=self.get_property("directory_prefix"), + default_exposure_time=self.detector_hwobj.get_default_exposure_time(), + minimum_exposure_time=self.detector_hwobj.get_minimum_exposure_time(), + detector_fileext=self.detector_hwobj.get_file_suffix(), + detector_type=self.detector_hwobj.get_detector_type(), + detector_manufacturer=self.detector_hwobj.get_manufacturer(), + detector_model=self.detector_hwobj.get_model(), + detector_px=det_px, + detector_py=det_py, + detector_binning_mode=self.detector_hwobj.get_binning_mode(), + undulators=undulators, + focusing_optic=self.get_property('focusing_optic'), + monochromator_type=self.get_property('monochromator'), + beam_divergence_vertical=self.beam_info_hwobj.get_beam_divergence_hor(), + beam_divergence_horizontal=self.beam_info_hwobj.get_beam_divergence_ver(), + polarisation=self.get_property('polarisation'), + input_files_server=self.get_property("input_files_server")) + + self.emit("collectConnected", (True,)) + self.emit("collectReady", (True, )) + + #self.logger.debug('*** bypass shutters: %s', type(os.environ.get('MXCUBE_BYPASS_SHUTTERS'))) + self.bypass_shutters = os.environ.get('MXCUBE_BYPASS_SHUTTERS') + #self.logger.debug('*** bypass shutters: %s', self.bypass_shutters) + if self.bypass_shutters and self.bypass_shutters.lower() == 'true': + self.logger.warning("Simulation mode: BYPASSING the SHUTTERS") + self.bypass_shutters = True + + self.rescorner = self.get_channel_object("rescorner_position") + + def pre_collect_check(self): + #CHECK if files exist, exit if true + full_path = self.get_image_file_name( + self.current_dc_parameters['oscillation_sequence'][0]['start_image_number'] + ) + if os.path.exists( full_path ): + msg = "Filename already exists : %s" % full_path + self.data_collection_failed( Exception(msg) , msg ) + + if HWR.beamline.session.get_proposal() == 'local-user': + msg = "You are not logged in, log in first" + self.data_collection_failed( Exception(msg) , msg ) + + + def do_collect(self, owner): + """ + Actual collect sequence + """ + + log = logging.getLogger("user_level_log") + log.info("Collection: Preparing to collect") + + try: + + self.pre_collect_check() + + self.emit("collectReady", (False,)) + self.emit( + "collectOscillationStarted", + (owner, None, None, None, self.current_dc_parameters, None), + ) + self.emit("progressInit", ("Collection", 100, False)) + self.collection_id = None + + ## ---------------------------------------------------------------- + ## Prepare data collection + + self.open_detector_cover() + self.open_safety_shutter() + #self.open_fast_shutter() # done through trigger for external trigger, open_fast_shutter_for_internal_trigger is used for internal trigger + + self.current_dc_parameters["status"] = "Running" + self.current_dc_parameters["collection_start_time"] = time.strftime( + "%Y-%m-%d %H:%M:%S" + ) + + # ---------------------------------------------------------------- + # Set data collection parameters + + if "transmission" in self.current_dc_parameters: + log.info( + "Collection: Setting transmission to %.2f", + self.current_dc_parameters["transmission"], + ) + self.set_transmission(self.current_dc_parameters["transmission"]) + + if "wavelength" in self.current_dc_parameters: + log.info( + "Collection: Setting wavelength to %.4f", + self.current_dc_parameters["wavelength"], + ) + self.set_wavelength(self.current_dc_parameters["wavelength"]) + + elif "energy" in self.current_dc_parameters: + log.info( + "Collection: Setting energy to %.4f", + self.current_dc_parameters["energy"], + ) + self.set_energy(self.current_dc_parameters["energy"]) + + dd = self.current_dc_parameters.get("resolution") + if dd and dd.get('upper'): + resolution = dd["upper"] + log.info("Collection: Setting resolution to %.3f", resolution) + self.set_resolution(resolution) + + elif "detector_distance" in self.current_dc_parameters: + log.info( + "Collection: Moving detector to %.2f", + self.current_dc_parameters["detector_distance"], + ) + self.move_detector(self.current_dc_parameters["detector_distance"]) + + # ---------------------------------------------------------------- + # Store information in LIMS + + log.info("Collection: Storing data collection in LIMS") + self.store_data_collection_in_lims() + + logging.getLogger("HWR").info( + "Collection parameters: %s" % str(self.current_dc_parameters) + ) + + if ( + self.current_dc_parameters['processing_online'] + and HWR.beamline.online_processing is not None + ): + HWR.beamline.online_processing.params_dict["collection_id"] = self.current_dc_parameters["collection_id"] + self.online_processing_task = gevent.spawn( + HWR.beamline.online_processing.run_processing, + self.current_dc_parameters + ) + + log.info( + "Collection: Creating directories for raw images and processing files" + ) + self.create_file_directories() + + log.info("Collection: Getting sample info from parameters") + self.get_sample_info() + + log.info("Collection: Storing sample info in LIMS") + self.store_sample_info_in_lims() + + if all( + item is None for item in self.current_dc_parameters["motors"].values() + ): + # No centring point defined + # create point based on the current position + current_diffractometer_position = ( + HWR.beamline.diffractometer.get_positions() + ) + for motor in self.current_dc_parameters["motors"].keys(): + self.current_dc_parameters["motors"][ + motor + ] = current_diffractometer_position.get(motor) + + # ---------------------------------------------------------------- + # Move to the centered position and take crystal snapshots + + log.info("Collection: Moving to centred position") + self.move_to_centered_position() + self.take_crystal_snapshots() + self.move_to_centered_position() + + self.prepare_acquisition() + + # ---------------------------------------------------------------- + # Site specific implementation of a data collection + + # In order to call the hook with original parameters + # before update_data_collection_in_lims changes them + # TODO check why this happens + + self.data_collection_hook() + + # ---------------------------------------------------------------- + # Store information in LIMS + + log.info("Collection: Updating data collection in LIMS") + self.update_data_collection_in_lims() + + except: + exc_type, exc_value, exc_tb = sys.exc_info() + failed_msg = "Data collection failed!\n%s" % exc_value + import traceback + failed_msg += traceback.format_exc() + self.collection_failed(failed_msg) + else: + self.collection_finished() + finally: + self.data_collection_cleanup() + + def data_collection_hook(self): + """Main collection hook, called from do_collect in AbstractCollect + """ + + self.logger.info("Running Xaloc data collection hook") + + #if not self.resolution_hwobj.is_ready(): + #self.logger.info("Waiting for resolution ready...") + #self.resolution_hwobj.wait_ready() + #if not self.detector_hwobj.is_ready(): + self.logger.info("Waiting for detector distance ready...") + self.detector_hwobj.wait_move_distance_done() + if not self.energy_hwobj.is_ready(): + self.logger.info("Waiting for energy ready...") + self.energy_hwobj.wait_move_energy_done() + + # First, save current parameters to revert back when done/fails + for motorname in self.scan_all_motor_names: # TODO: check if this is the right place to add these values. Ideally this should be done right after the collect click + self.logger.info('Inital motor velocity of motor %s = %.4f' % ( + motorname, + self.scan_motors_hwobj[motorname].get_velocity() + ) + ) + self.scan_init_velocities[motorname] = self.scan_motors_hwobj[motorname].get_velocity() + self.scan_init_positions[motorname] = self.scan_motors_hwobj[motorname].get_value() + self.omega_init_pos = self.omega_hwobj.get_value() + self.omega_init_vel = 60 # self.omega_hwobj.get_velocity() + + #self.logger.info('Inital motor velocities dict %s' % str(self.scan_init_velocities) ) + #self.logger.info('Inital omega velocity value %.1f' % self.omega_init_vel ) + + # pass wavelength needed in auto processing input files + osc_seq = self.current_dc_parameters['oscillation_sequence'][0] + osc_seq['wavelength'] = self.get_wavelength() + self.logger.info('osc_seq %s' % str(osc_seq) ) + self.logger.debug("current_dc_parameters %s" % str( self.current_dc_parameters ) ) + + self.current_dc_parameters['detector_binning_mode'] = ['EXTERNAL_TRIGGER'] + + first_image_no = osc_seq['start_image_number'] + exp_period = osc_seq['exposure_time'] + img_range = osc_seq['range'] + omega_speed = 60 # initial the speed value, this will be recalculated later on in prepare_acquisition + omega_pos = osc_seq['start'] + nb_images = osc_seq['number_of_images'] + sweep_nb_images = nb_images + total_collection_time = exp_period * nb_images + + if self.aborted_by_user: + self.emit_collection_failed("Aborted by user") + self.aborted_by_user = False + return + + + self.prepare_detector_for_acquisition() + + ### EDNA_REF, OSC, MESH, HELICAL + + exp_type = self.current_dc_parameters['experiment_type'] + self.logger.debug("Collection method selected is %s" % exp_type) + + if exp_type == "Characterization": + self.logger.debug("Running a collect (CHARACTERIZATION)") + elif exp_type == "Helical": + self.scan_move_motor_names = [] + self.logger.debug("Running a helical collection") + self.logger.debug( + "\thelical start positions are: %s" % str( + self.scan_start_positions)) + self.logger.debug( + "\thelical end positions are: %s" % str( + self.scan_end_positions)) + self.scan_move_motor_names = [] + self.set_scan_move_motors(self.scan_start_positions, self.scan_end_positions) + self.scan_velocities = self.calculate_scan_velocities( + self.scan_start_positions, self.scan_end_positions, total_collection_time + ) + self.logger.info('Preliminary helical setup completed') + elif exp_type == "Mesh": + slow_mxcube_motor_name, fast_mxcube_motor_name, fast_motor_nr_images, slow_motor_nr_images = \ + self.setMeshScanParameters( + osc_seq, + self.mesh_mxcube_horizontal_motor_name, + self.mesh_mxcube_vertical_motor_name, + self.mesh_center, + self.mesh_range + ) + else: + self.logger.debug("Running a collect (STANDARD)") + + if self.check_scan_velocities( self.scan_velocities ): # There are motors that cant work at required speed + msg = 'Cant reach the required velocities' + self.data_collection_failed( Exception( msg ), msg ) + + try: + init_pos, final_pos, total_dist, omega_speed = self.calc_omega_scan_values( + omega_pos, + sweep_nb_images + ) + + # RB init_pos and final_pos include the ramp up and run out range for omega + except Exception as e: + self.user_logger.error("calc_omega_scan_values failed") + self.logger.error('error %s' % str(e) ) + #self.user_logger.error('error %s' % repr( e ) ) + self.data_collection_failed( e, "calc_omega_scan_values failed" ) + + self.logger.debug(' Sweep parameters omega: init %s start %s total dist %s speed %s' % + (init_pos, omega_pos, total_dist, omega_speed ) + ) + + self._collecting = True + # for progressBar brick + self.emit("progressInit", "Collection", osc_seq['number_of_images']) + + self.emit("collectStarted", (None, 1)) # parameters required are owner and nr of sweeps + + if exp_type == 'OSC' or (exp_type == 'Characterization' and nb_images == 1) or exp_type == 'Helical': + # prepare input files for autoprocessing + if exp_type != "Characterization": + self.autoprocessing_hwobj.create_input_files(self.current_dc_parameters) + + # Sardana collect: run ascanct + self.collect_prepare_omega( init_pos, omega_speed ) + final_pos = self.prepare_collection( + start_angle=omega_pos, + nb_images=nb_images, + img_range=img_range, + first_image_no=first_image_no, + exp_time = exp_period - self.detector_hwobj.get_latency_time(), + omega_speed = omega_speed + ) + # omega_speed, start_pos, final_pos, nb_images, first_image_no + self.collect_images( + omega_speed, omega_pos, final_pos, nb_images,first_image_no + ) + elif exp_type == 'Characterization' and nb_images > 1: # image one by one + for imgno in range(nb_images): + # Sardana collect, run ascanct + self.collect_prepare_omega( init_pos, omega_speed ) + final_pos = self.prepare_collection( + start_angle=omega_pos, + nb_images=1, + img_range=img_range, + first_image_no=first_image_no, + exp_time = exp_period - self.detector_hwobj.get_latency_time(), + omega_speed = omega_speed + ) + self.collect_images( + omega_speed, omega_pos, final_pos, 1, first_image_no + ) + first_image_no += 1 + omega_pos += 90 + + # + # + # START of 20210218: Lines only necessary for ni660 collects, remove when switching to pure meshct/ascanct scans + + init_pos, final_pos, total_dist, omega_speed = self.calc_omega_scan_values( omega_pos, nb_images ) + # END of lines for ni660 scans + # + # + + elif exp_type == 'Mesh': # combine all collections + self.logger.debug("Running a raster collection") + #self.write_image_headers(omega_pos) + self.collect_mesh( + 'test_pilatus_omegax_scan', + first_image_no, + fast_mxcube_motor_name, + fast_motor_nr_images, + slow_mxcube_motor_name, + slow_motor_nr_images, + self.mesh_range, + exp_period, + self.mesh_center + ) + #self.finalize_mesh_scan() + + # Collect images using direct configuration of the ni660 card + def collect_images(self, omega_speed, start_pos, final_pos, nb_images, first_image_no): + """ + Run a single wedge. + Start position is the omega position where images should be collected. + It is assumed omega is already at the initial position, which comes before the start position + and allows the mechanics to get up to speed + """ + self.logger.info("collect_images: Collecting images, by moving omega to %s" % final_pos) + total_time = (final_pos - self.omega_hwobj.get_value() ) / omega_speed # assumes omega is already at start position for collection + self.logger.info(" Total collection time = %s" % total_time) + + margin_deg = 0.1 + final_pos += margin_deg + + # Now collect the data + self.detector_hwobj.start_collection() + + if omega_speed != 0: + try: + self.logger.info(" Moving omega to final position = %.4f" % final_pos ) + self.omega_hwobj.set_value( final_pos ) + except Exception as e: + self.data_collection_failed( e, 'Cant move omega to position %.6f' % final_pos ) + else: + try: + self.open_fast_shutter_for_internal_trigger() + except Exception as e: + self.data_collection_failed( e, 'MXCuBE is not prepared to collect still images' ) + + if self.current_dc_parameters['experiment_type'] == 'Helical': + self.wait_start_helical_motors() + + self.wait_collection_done(first_image_no, nb_images + first_image_no - 1, total_time) + + def collect_mesh( + self, + measurement_group, # ised only for sardana scans + first_image_no, + mesh_mxcube_fast_motor_name, + mesh_num_frames_per_line, + mesh_mxcube_slow_motor_name, + mesh_num_lines, + mesh_range, + time_interval, + mesh_center + ): + """ + mesh scan using Sardana ascanct. It is assumed that the fast motor and slow motor move in a positive direction + The mesh scan does an S shape when sshape is true. + """ + + # Since pilatus3 the images do not start with number 1 + #self.detector_hwobj.chan_saving_next_number.set_value(first_image_no) + # Calculate motor steps + mov_fast_step = mesh_range[self.mesh_fast_index] / float( mesh_num_frames_per_line ) + mov_slow_step = 0 + if mesh_num_lines > 1: mov_slow_step = mesh_range[self.mesh_slow_index] / float( mesh_num_lines - 1 ) + + local_slow_start_pos = self.scan_start_positions[ mesh_mxcube_slow_motor_name ] + local_first_image_no = first_image_no + mesh_xaloc_fast_motor_name = self.xaloc_motor_names_dict[ mesh_mxcube_fast_motor_name ] + fast_motor_hwo = self.scan_motors_hwobj[ mesh_mxcube_fast_motor_name ] + # Calculate motor margin to start up + # x_constant_vel = vel_0 * t_acc + 1 / 2. * (acc) * (t_acc**2) + #margin_mm = fast_motor_hwo.get_acceleration() + margin_mm = 0.025 # margin in mm for the motor to get to speed + + # final_pos is end of omega range (not including safedelta) + detdeadtime = self.detector_hwobj.get_latency_time() + total_time = mesh_num_frames_per_line * mesh_num_lines * time_interval + + local_fast_start_pos = self.scan_start_positions[ mesh_mxcube_fast_motor_name ] + local_fast_end_pos = self.scan_end_positions[ mesh_mxcube_fast_motor_name ] + self.scan_motors_hwobj[ mesh_mxcube_slow_motor_name ].set_value( local_slow_start_pos, timeout = 10 ) + + self.logger.debug("Running a raster collection, fast motor range is from %.4f to %.4f " % (local_fast_start_pos, local_fast_end_pos)) + + #TODO fix the numbering of the files + self.prepare_sardana_env( measurement_group ) + sshape = self.mesh_sshaped_bool + fast_scan_direction = 1 + + if not self.use_sardana_scan: + # mv omegax to starting position + self.logger.debug("Moving fast scan motor %s to %.4f" % ( mesh_xaloc_fast_motor_name, local_fast_start_pos - margin_mm ) ) + fast_motor_hwo.set_value( + local_fast_start_pos - margin_mm, + timeout = 10 + ) + fast_motor_hwo.wait_end_of_move( timeout = 30 ) + fast_motor_hwo.wait_ready( timeout = 5 ) + + # Calculate motor velocity + saved_scan_motor_velocity = fast_motor_hwo.get_velocity() + required_scan_motor_velocity = math.fabs( + (local_fast_end_pos - local_fast_start_pos) / (mesh_num_frames_per_line * time_interval) + ) + self.logger.debug("Calculated velocity for the fast scan motor %.4f" % ( required_scan_motor_velocity ) ) + fast_motor_hwo.set_velocity( required_scan_motor_velocity ) + fast_motor_hwo.wait_ready( timeout = 5 ) + + for lineno in range( mesh_num_lines ): + if self.aborted_by_user: + self.logger.info("User interruption of data collection during mesh scan detected, aborting mesh scan" ) + break # cleanup will be handled in stop_collect + else: + self.logger.debug("\t line %s out of %s" % ( lineno + 1, mesh_num_lines ) ) + + #TODO: fix image headers + self.write_image_headers( 0 ) + + #TODO move omegax/phiy to starting position of collection (OR is this done in the MxCube sequence somewhere??? + # Sardana will move the motor back to the inital position after the scan. Two consecuences: + # the fast motor will always go back the same position after each scan, so better move it to the start position of the scan to prevent excessive movements + + + self.logger.debug("mesh_xaloc_fast_motor_name = %s\nlocal_fast_start_pos = %.4f\nlocal_fast_end_pos = %.4f\nmov_fast_step = %.4f\ntime_interval - detdeadtime = %.4f\ndetdeadtime = %.4f\nfirst_image_no = %d\nmesh_num_frames_per_line = %d" % ( + mesh_xaloc_fast_motor_name, + local_fast_start_pos, + local_fast_end_pos, + mov_fast_step, + time_interval - detdeadtime, + detdeadtime, + local_first_image_no, + mesh_num_frames_per_line + ) + ) + gevent.sleep(0.1) + if self.use_sardana_scan: + self.run_ascanct( + mesh_xaloc_fast_motor_name, + local_fast_start_pos, + local_fast_end_pos, + mov_fast_step, + time_interval, + detdeadtime, + local_first_image_no, + mesh_num_frames_per_line + ) + else: + self.run_line_scan( + mesh_xaloc_fast_motor_name, + mesh_mxcube_fast_motor_name, + local_fast_start_pos, + local_fast_end_pos, + time_interval, # exp period + detdeadtime, + local_first_image_no, + mesh_num_frames_per_line, + margin_mm, + fast_scan_direction + ) + + local_first_image_no += mesh_num_frames_per_line + if lineno == mesh_num_lines-1: + break + + self.scan_motors_hwobj[ mesh_mxcube_slow_motor_name ].set_value( + self.scan_motors_hwobj[ mesh_mxcube_slow_motor_name ].get_value() \ + + mov_slow_step , + timeout = 10 + ) + + if sshape: + dummy = local_fast_start_pos + local_fast_start_pos = local_fast_end_pos + local_fast_end_pos = dummy + fast_scan_direction *= -1 + + self.scan_motors_hwobj[ mesh_mxcube_slow_motor_name ].wait_ready() + # move motors to center of scan + if not self.use_sardana_scan: + fast_motor_hwo.wait_end_of_move( timeout = ( time_interval * mesh_num_frames_per_line) + 5 ) + fast_motor_hwo.wait_ready( timeout = (time_interval * mesh_num_frames_per_line) + 5 ) + # Calculate motor velocity + self.logger.debug("Resetting velocity of the fast scan motor %.4f" % ( saved_scan_motor_velocity ) ) + fast_motor_hwo.set_velocity( saved_scan_motor_velocity ) + fast_motor_hwo.wait_ready( timeout = 5 ) + + if self.current_dc_parameters['processing_online'] != "XrayCentering": + self.move_motors( mesh_center.as_dict() ) + self.go_to_sampleview() + + self.wait_collection_done(first_image_no, first_image_no + ( mesh_num_frames_per_line * mesh_num_lines ) - 1, total_time + 5) + if self.current_dc_parameters['processing_online'] == "XrayCentering": + self.wait_online_processing_done() + + # omega_speed and det_trigger are not necessary for sardanized collections + def prepare_collection(self, start_angle, nb_images, img_range, first_image_no, exp_time, omega_speed ): + osc_seq = self.current_dc_parameters['oscillation_sequence'][0] + + total_dist = float ( nb_images * img_range ) + final_pos = start_angle + total_dist + + self.logger.info("nb_images: %s / total_distance: %s " % + ( nb_images, total_dist ) + ) + + self.write_image_headers(start_angle) + + for scanmovemotorname in self.scan_move_motor_names: + self.logger.info("Setting %s velocity to %.4f" % (scanmovemotorname, self.scan_velocities[scanmovemotorname]) ) + try: + #self._motor_persistently_set_velocity(self.scan_motors_hwobj[scanmovemotorname], self.scan_velocities[scanmovemotorname]) + self.scan_motors_hwobj[scanmovemotorname].set_velocity( self.scan_velocities[scanmovemotorname] ) + except Exception as e: + self.logger.info("Cant set the scan velocity of motor %s" % scanmovemotorname ) + self.data_collection_failed( e, "Cant set the scan velocity of motor %s" % scanmovemotorname ) + + # + # + # START of 20210218: Lines only necessary for ni660 collects, remove when switching to pure meshct/ascanct scans + try: + self.detector_hwobj.prepare_collection( nb_images, first_image_no, exp_time ) + except Exception as e : + self.logger.error( str(e) ) + self.user_logger.error("Cannot prepare the detector, does the image exist? If not, check the detector state" ) + self.data_collection_failed( e, "Cannot prepare the detector" ) + + if self.current_dc_parameters['experiment_type'] != 'Mesh': + self.logger.debug( "Setting detector binning mode %s" % self.current_dc_parameters['detector_binning_mode'][0] ) + self.detector_hwobj.set_binning_mode( self.current_dc_parameters['detector_binning_mode'][0] ) + if omega_speed != 0 : + self.configure_ni(start_angle, total_dist, 'omega', self.omega_hwobj.get_acceleration() ) + + # END of lines for ni660 scans + # + # + + #TODO it doesnt make sense that prepare_collection returns some of these numbers, reorganize! + return final_pos + + def prepare_sardana_env( self, measurement_group ): + # This is repeated code: occurs in write_image_headers and wait_save_image + # Set the appropriate environment variables + # TODO: the time.sleeps are necessary to wait for the door to recover. Make a while loop to check for doors ON. see ./HardwareRepository/Command/Sardana.py + fileinfo = self.current_dc_parameters['fileinfo'] + basedir = fileinfo['directory'] + template = fileinfo['template'] # prefix_1_%04d.cbf + if self.use_sardana_scan: + # save the images to the write place + sardtemplate = template.split('%')[0] + \ + "{index:%02d}" % int(template.split('%')[-1].split('d')[0]) + \ + template.split('%')[-1].split('d')[1] + savingpattern = 'file://' + os.path.join( basedir , sardtemplate ) + self.logger.info("savingpattern = %s" % savingpattern) + self.logger.info("setting ActiveMntGrp") + self.logger.info("setting pilatus saving pattern") + #self.set_pilatus_saving_pattern( measurement_group, savingpattern, wait=True) + self.set_pilatus_saving_pattern( 'ValueRefEnabled', True, 'pilatus_image', measurement_group, wait=True) + self.set_pilatus_saving_pattern( 'ValueRefPattern', savingpattern, 'pilatus_image', measurement_group, wait=True) + #self.logger.debug("set_pilatus_saving_pattern.doorstate = %s" % self.set_pilatus_saving_pattern.doorstate ) + self.senv('ActiveMntGrp', measurement_group, wait=True) + time.sleep(0.1) + + + # save the collection details + self.logger.info("setting ScanDir") + self.senv( 'ScanDir', basedir, wait=True ) + time.sleep(0.1) + self.logger.info("setting ScanFile") + self.senv( 'ScanFile ' + str( template.split('_%')[0] + '.dat'), wait=True ) + time.sleep(0.1) + + #def run_meshct( + #self, + #first_image_no, + #mesh_mxcube_horizontal_motor_name, + #fast_motor_nr_images, + #mesh_mxcube_vertical_motor_name, + #slow_motor_nr_images, + #time_interval, + #sshaped_bool, + #deadtime + #): + ##meshct + ##Parameters: + ##motor1 : (Moveable) First motor to move (generates triggers, fast motor) + ##m1_start_pos : (Float) Scan start position for first motor + ##m1_final_pos : (Float) Scan final position for first motor + ##m1_nr_interv : (Integer) Number of scan intervals + ##motor2 : (Moveable) Second motor to move + ##m2_start_pos : (Float) Scan start position for second motor + ##m2_final_pos : (Float) Scan final position for second motor + ##m2_nr_interv : (Integer) Number of scan intervals + ##integ_time : (Float) Integration time + ##bidirectional : (Boolean) Save time by scanning s-shaped + ##latency_time : (Float) Latency time + #self.logger.debug("meshct parameters:") + #self.logger.debug(" fast_motor_name: %s" % mesh_mxcube_horizontal_motor_name) + #self.logger.debug(" xaloc fast_motor_name: %s" % self.xaloc_motor_names_dict[mesh_mxcube_horizontal_motor_name]) + #self.logger.debug(" fast_motor_start_pos: %s" % self.scan_start_positions[mesh_mxcube_horizontal_motor_name]) + #self.logger.debug(" fast_motor_end_pos: %s" % self.scan_end_positions[mesh_mxcube_horizontal_motor_name]) + #self.logger.debug(" fast_motor_nr_images: %s" % fast_motor_nr_images) + #self.logger.debug(" slow_motor_name: %s" % mesh_xaloc_slow_motor_name) + #self.logger.debug(" xaloc slow_motor_name: %s" % self.xaloc_motor_names_dict[mesh_mxcube_vertical_motor_name]) + #self.logger.debug(" slow_motor_start_pos: %s" % self.scan_start_positions[mesh_mxcube_vertical_motor_name]) + #self.logger.debug(" slow_motor_end_pos: %s" % self.scan_end_positions[mesh_mxcube_vertical_motor_name]) + #self.logger.debug(" slow_motor_nr_images: %s" % slow_motor_nr_images) + #self.logger.debug(" time_interval: %.4f" % time_interval) + #self.logger.debug(" sshaped_bool: %s" % sshaped_bool) + #self.logger.debug(" deadtime: %.4f" % deadtime) + + # TODO: include the first image as a parameter + #self.meshct( + #self.xaloc_motor_names_dict[mesh_mxcube_horizontal_motor_name], + #self.scan_start_positions[mesh_mxcube_horizontal_motor_name], + #self.scan_end_positions[mesh_mxcube_horizontal_motor_name], #start pos of fast motor for last data point + #fast_motor_nr_images - 1, + #self.xaloc_motor_names_dict[mesh_mxcube_vertical_motor_name], + #self.scan_start_positions[mesh_mxcube_vertical_motor_name], + #self.scan_end_positions[mesh_mxcube_vertical_motor_name], #start pos of slow motor for last data point + #slow_motor_nr_images - 1, + #time_interval - deadtime, + #sshaped_bool, # True: up and down scans, False: only up scans + #deadtime + #) + #total_time = fast_motor_nr_images * fast_motor_nr_images * ( time_interval + deadtime ) + + #self.wait_collection_done(first_image_no-1, fast_motor_nr_images * slow_motor_nr_images - 1, total_time + 5) # TODO: allow for start at higher image numbers + #self.collection_finished() + + + def run_ascanct(self, moveable, start_pos, final_pos, deg_interval, time_interval, deadtime, first_image_no, nb_images): + if self.aborted_by_user: + self.logger.info("User interruption of data collection during mesh scan detected, aborting ascanct" ) + return # cleanup will be handled in data_collection_cleanup + + self.logger.info( "Collecting images using the ascanct macro" ) + total_time = time_interval * (final_pos - start_pos) / deg_interval + + if final_pos < start_pos: deg_interval = - deg_interval + + self.logger.debug("moveable %s" % moveable ) + self.logger.debug("start_pos %.4f" % start_pos ) + self.logger.debug("final_pos - deg_interval %.4f " % (final_pos - deg_interval) ) + self.logger.debug("nb_images - 1 %d" % ( nb_images - 1 ) ) + self.logger.debug("time_interval - deadtime %.4f" % ( time_interval - deadtime ) ) + self.logger.debug("deadtime %.4f" % ( deadtime ) ) + + #TODO: Set the first image number here + self.mxcube_sardanascan_running = True + self.ascanct(moveable, + start_pos, + final_pos - deg_interval, + nb_images - 1, + time_interval - deadtime, + deadtime, + wait = True + ) + self.mxcube_sardanascan_running = False + + + def run_line_scan( + self, + mesh_xaloc_fast_motor_name, + mesh_mxcube_fast_motor_name, + local_fast_start_pos, + local_fast_end_pos, + exp_period, + detdeadtime, + local_first_image_no, + mesh_num_frames_per_line, + margin_mm, + fast_scan_direction + ): + #initialize local pars + self.mxcube_sardanascan_running = True # tell mxcube that we are running a line scan, not only for sardanascan! + manage_shutter_locally = False #TODO: fix the shutterchannel for the ni660 poschan ctr6 + + # To show intermediate images + intermediate_image_number = local_first_image_no + intermediate_image_step = max( int (0.1 / exp_period), 1) + + if mesh_mxcube_fast_motor_name == 'phiz': + manage_shutter_locally = False + + fast_motor_hwo = self.scan_motors_hwobj[ mesh_mxcube_fast_motor_name ] + fast_motor_hwo.wait_end_of_move( timeout = ( exp_period * mesh_num_frames_per_line) + 5 ) + fast_motor_hwo.wait_ready( timeout = (exp_period * mesh_num_frames_per_line) + 5 ) + + margin_mm *= fast_scan_direction + self.logger.debug("Fast scan motor %s at initial position %.4f" % + ( mesh_xaloc_fast_motor_name, fast_motor_hwo.get_value() ) + ) + + + # configure NI6602. TODO: This may not be necessary for each line. Configuring once, and then invert the line direction might be enough + try: + self.configure_ni( + local_fast_start_pos, # position where detector should be triggered + math.fabs(local_fast_end_pos - local_fast_start_pos), + mesh_xaloc_fast_motor_name, + 0.001, # override acceleration. TODO: which acceleration time is correct for omegax? + ) + except Exception as e: + self.data_collection_failed( e, "Can't configure the trigger ni660 card") + + # set collection pars in detector + try: + self.logger.debug("Preparing detector for line scan collection, lima ready is %s" % self.detector_hwobj.chan_lima_ready.get_value() ) + self.detector_hwobj.prepare_collection( mesh_num_frames_per_line, local_first_image_no, exp_period - detdeadtime ) + except Exception as e: + self.logger.error( str(e) ) + self.user_logger.error("Cannot prepare the detector, does the image exist? If not, check the detector state" ) + self.data_collection_failed( e, "Cannot prepare the detector, does the image exist? If not, check the detector state" ) + + # arm detector + #self.logger.debug("Arm detector for line scan collection" ) + self.detector_hwobj.start_collection() + #gevent.sleep(1) + # mv omegax + if manage_shutter_locally:#TODO: fix the shutterchannel for the ni660 poschan ctr6 + self.logger.debug("Opening shutter manually " ) + self.open_fast_shutter_for_internal_trigger() + sleep_time = 0.1 + self.logger.debug("Sleeping for %.2f secs" % sleep_time ) + gevent.sleep( sleep_time ) + self.logger.debug("Waking up" ) + self.logger.debug("Moving fast scan motor %s from %.4f to end of line at %.4f" % \ + ( mesh_xaloc_fast_motor_name, fast_motor_hwo.get_value(), local_fast_end_pos + margin_mm ) + ) + fast_motor_hwo.set_value( + local_fast_end_pos + margin_mm, + ) + # wait collection_done + #fast_motor_hwo.wait_end_of_move( timeout = ( exp_period * mesh_num_frames_per_line) + 1 ) + #fast_motor_hwo.wait_ready( timeout = (exp_period * mesh_num_frames_per_line) + 5 ) + while fast_scan_direction * ( local_fast_end_pos - fast_motor_hwo.get_value() ) > 0.001 and not self.aborted_by_user: + time.sleep(0.005) + intermediate_image = self.get_image_file_name( intermediate_image_number ) + #self.logger.debug("Waiting for intermediate image %s" % ( intermediate_image ) ) + if intermediate_image_number < mesh_num_frames_per_line: + #self.logger.debug(" waiting for image on disk: %s" % intermediate_image) + while not os.path.exists(intermediate_image) and not self.aborted_by_user: + time.sleep(0.005) + self.image_tracking_hwobj.load_image(intermediate_image) + intermediate_image_number += intermediate_image_step + + if manage_shutter_locally:#TODO: fix the shutterchannel for the ni660 poschan ctr6 + self.fastshut_hwobj.close() #TODO: fix the shutterchannel for the ni660 poschan ctr6 + #self.detector_hwobj.wait_running(timestep = 0.025, timeout = 5) + #self.detector_hwobj.wait_standby(timestep = 0.05, timeout = mesh_num_frames_per_line * exp_period + 5) + #self.logger.debug("detector cam_state %s, lima ready %s, " % + #(self.detector_hwobj.get_cam_state(), self.detector_hwobj.chan_lima_ready.get_value() ) + #) + self.mxcube_sardanascan_running = False # tell mxcube that we are running a line scan, not only for sardanascan! + + #self.detector_hwobj.wait_ready() + self.unconfigure_ni() + #self.detector_hwobj.stop_collection() + + def calc_omega_scan_values( self, omega_start_pos, nb_images ): + """ + Calculates the values at which the omega should start and end so that + during collection it has a constant speed + """ + osc_seq = self.current_dc_parameters['oscillation_sequence'][0] + + img_range = osc_seq['range'] + exp_time = osc_seq['exposure_time'] + + total_dist = float ( nb_images * img_range ) + total_time = float ( nb_images * exp_time ) + omega_acceltime = self.omega_hwobj.get_acceleration() + omega_speed = float( total_dist / total_time ) + + # TODO: for mesh scans, this range is way to big + safe_delta = 1 + if self.current_dc_parameters['experiment_type'] == 'Mesh': + safe_delta = 0.5 + else: + safe_delta = 9.0 * omega_speed * omega_acceltime + + init_pos = omega_start_pos - safe_delta + final_pos = omega_start_pos + total_dist + safe_delta #TODO adjust the margins to the minimum necessary + + return ( init_pos, final_pos, total_dist, omega_speed ) + + + def collect_prepare_omega(self, omega_pos, omega_speed): + ''' + Prepares omega for sweep. + - Sets the velocity to the fast speed + - Moves omega to the initial position ( required by ni card) + - Sets the velocity to the collect speed + ''' + + try: + self.logger.info("Setting omega velocity to its nominal value") + self.omega_hwobj.set_velocity( 60 ) + except Exception as e : + self.logger.error("Error setting omega velocity, state is %s" % str(self.omega_hwobj.get_state())) + self.data_collection_failed( e, 'Omega velocity could not be set' ) + + self.logger.info("Moving omega to initial position %s" % omega_pos) + try: + if math.fabs(self.omega_hwobj.get_value() - omega_pos) > 0.0001: + self.omega_hwobj.set_value( omega_pos, timeout = 30 ) + # TODO: check why both of the following checks are necessary for the omega to be ready + self.omega_hwobj.wait_end_of_move( timeout = 30 ) + self.omega_hwobj.wait_ready( timeout = 2 ) + + except Exception as e : + self.logger.info("Omega state is %s" % str(self.omega_hwobj.get_state())) + self.data_collection_failed( e, 'Omega position could not be set' ) + + self.logger.info("Setting omega velocity to %s and is ready %s" % (omega_speed, self.omega_hwobj.is_ready() ) ) + self.logger.info("Omega state is %s, ready is %s" % (str(self.omega_hwobj.get_state()), self.omega_hwobj.is_ready()) ) + + try: + self.omega_hwobj.set_velocity( omega_speed ) + except Exception as e: + self.logger.debug("Omega state is %s" % str(self.omega_hwobj.get_state())) + self.data_collection_failed( e, "Cannot set the omega velocity to %s" % omega_speed ) + + return + + def wait_start_helical_motors( self): + timestep = 1 # secs + timeout = 10 # secs + self.detector_hwobj.wait_running( timestep, timeout ) # once the detector is running (collection started), start the helical motors + for scanmovemotorname in self.scan_move_motor_names: + try: + # It might be faster (but more dangerous) + self.scan_motors_hwobj[scanmovemotorname].position_channel.set_value( self.scan_end_positions[scanmovemotorname] ) + # the safer option: + #self.scan_motors_hwobj[scanmovemotorname].set_value( self.scan_end_positions[scanmovemotorname] ) + + #self.logger.info('Moving motor %s from %.4f to final position %.4f at %.6f velocity' % + # (scanmovemotorname, self.scan_start_positions[scanmovemotorname], + # self.scan_end_positions[scanmovemotorname], + # self.scan_velocities[scanmovemotorname] ) ) + except Exception as e: + self.data_collection_failed( e, 'Cannot move the helical motor %s to its end position' % scanmovemotorname ) + + + + def data_collection_failed(self, exception, failed_msg="XalocCollect: data_collection_failed"): + self.user_logger.error(failed_msg) + self.logger.debug("Data collection failed with error %s" % str( exception ) ) + self.logger.debug(" Initiating recovery sequence") + #TODO: this fails with list index out of range QueueManager line 149. + # This seems to be related with set_sardana_collect_env (see data_path_widget) + raise exception + + def prepare_acquisition(self): + """ + checks shutters, moves supervisor to collect phase, prepares detector and calculates omega start values + omega_start_pos should be the value at which the collection starts + """ + + fileinfo = self.current_dc_parameters['fileinfo'] + basedir = fileinfo['directory'] + self.check_directory(basedir) + + # Save omega velocity + # self.saved_omega_velocity = self.omega_hwobj.get_velocity() + # Better use it nominal velocity (to be properly defined in Sardana motor) + # Ensure omega has its nominal velocity to go to the initial position + # We have to ensure omega is not moving when setting the velocity + + # create directories if needed + + # check fast shutter closed. others opened + + # go to collect phase + if not self.is_collect_phase(): + self.logger.info("Supervisor not in collect phase, asking to go...") + success = self.go_to_collect() + if not success: + msg = "Supervisor cannot set COLLECT phase. Issue an Init in the diff and supervisor devices. Omegax should be between -1 and +1 mm" + self.data_collection_failed( Exception(msg), msg ) + + if self.bypass_shutters: + self.user_logger.warning("Shutters BYPASSED") + else: + _ok, failed = self.check_shutters() + if not _ok: + msg = "Shutter(s) {} NOT READY".format(failed) + self.user_logger.error(msg) + return _ok, msg + else: + self.user_logger.info("Shutters READY") + + gevent.sleep(1) + self.logger.info( + "Waiting diffractometer ready (is %s)" % str(self.diffractometer_hwobj.current_state)) + self.diffractometer_hwobj.wait_device_ready(timeout=10) # Is an exception generated upon timeout??? + self.logger.info("Diffractometer is now ready.") + + detok = self.detector_hwobj.get_cam_state() == 'STANDBY' + self.logger.info( 'Detector ok %s, cam_state = %s' % ( detok, self.detector_hwobj.get_cam_state() ) ) + + if not detok: + msg = "Cannot prepare the detector for acquisition, check the Pilatus cam_state. " + if self.detector_hwobj.get_cam_state() != 'SETTING_ENERGY': + msg += "Issuing a reset command in bl13/eh/pilatuslima, try again" + self.detector_hwobj.stop_acquisition() + else: msg += "The Pilatus is setting the energy, please be patient!!!" + self.user_logger.info( msg ) + self.data_collection_failed( Exception(msg), msg ) + + return + + def prepare_detector_for_acquisition(self): + + detok = False + try: + detok = self.detector_hwobj.prepare_acquisition(self.current_dc_parameters) + self.logger.info("Prepared detector for acquistion, detok = %s" % str( detok ) ) + except Exception as e: + msg = "Cannot prepare the detector for acquisition" + self.logger.error( msg ) + self.data_collection_failed( e, msg ) + + if not detok: + msg = "Cannot prepare the detector for acquisition" + self.logger.error( msg ) + self.data_collection_failed( Exception(msg), msg ) + + return detok + + def write_image_headers(self, start_angle): + # maintain for sardana scans? + fileinfo = self.current_dc_parameters['fileinfo'] + basedir = fileinfo['directory'] + + exp_type = self.current_dc_parameters['experiment_type'] + osc_seq = self.current_dc_parameters['oscillation_sequence'][0] + + nb_images = osc_seq['number_of_images'] + # start_angle = osc_seq['start'] + + try: img_range = osc_seq['range'] + except: img_range = 0 + + if exp_type == "Characterization": + #TODO set spacing according to the spacing used in collect, not a fixed value + angle_spacing = 90 + else: + angle_spacing = img_range + + exp_time = osc_seq['exposure_time'] + + # PROGRAM Image Headers + #latency_time = 0.003 + latency_time = self.detector_hwobj.get_latency_time() + limaexpt = exp_time - latency_time + + self.image_headers = {} + + angle_info = [start_angle, img_range, angle_spacing] + + self.image_headers['nb_images'] = nb_images + self.image_headers['Exposure_time'] = "%.4f" % limaexpt + self.image_headers['Exposure_period'] = "%.4f" % exp_time + self.image_headers['Start_angle'] = "%f deg." % start_angle + self.image_headers['Angle_increment'] = "%f deg." % img_range + self.image_headers['Wavelength'] = "%f A" % self.energy_hwobj.get_wavelength() + + self.image_headers["Detector_distance"] = "%.5f m" % ( + self.detector_hwobj.get_distance() / 1000.0) + self.image_headers["Detector_Voffset"] = '0 m' + + beamx, beamy = self.detector_hwobj.get_beam_position() + self.image_headers["Beam_xy"] = "(%.2f, %.2f) pixels" % (beamx, beamy) + + self.image_headers["Filter_transmission"] = "%.4f" % ( + self.transmission_hwobj.get_value() / 100.0) + self.image_headers["Flux"] = "%.4g" % self.flux_hwobj.get_flux() + self.image_headers["Detector_2theta"] = "0.0000" + self.image_headers["Polarization"] = "0.99" + self.image_headers["Alpha"] = '0 deg.' + + # TODO add XALOC phi (MXCuBE kappa_phi) to image headers + self.image_headers["Kappa"] = "%.4f deg." % self.chan_kappa_pos.get_value() + self.image_headers["Phi"] = "%.4f deg." % self.chan_phi_pos.get_value() + + self.image_headers["Chi"] = "0 deg." + self.image_headers["Oscillation_axis"] = "omega (X, CW)" + self.image_headers["N_oscillations"] = '1' + self.image_headers["Detector_2theta"] = "0.0000 deg" + + self.image_headers["Image_path"] = ': %s' % basedir + + self.image_headers["Threshold_setting"] = '%0f eV' %\ + self.detector_hwobj.get_threshold() + #self.image_headers["Gain_setting"] = '%s (vtr)' % str( + #self.detector_hwobj.get_gain()) + + self.image_headers["Tau"] = '%s s' % str(199.1e-09) + self.image_headers["Count_cutoff"] = '%s counts' % str(370913) + self.image_headers["N_excluded_pixels"] = '= %s' % str(1178) + self.image_headers["Excluded_pixels"] = ': %s' % str("/var/local/lib/dectris/config/calibration/Mask/badpix_mask.tif") + #### TODO find trim file for pilatus3X + #self.image_headers["Trim_file"] = ': %s' % str( + #"p6m0108_E12661_T6330_vrf_m0p20.bin") #TODO: pick up the true trim file!!!!! + + self.detector_hwobj.set_image_headers(self.image_headers, angle_info) + + def wait_collection_done(self, first_image_no, last_image_no, total_time): + + self.logger.info(" Total acquisition time = %.2f s" % total_time ) + self.logger.info(" last_image_no = %d" % last_image_no ) + + self.wait_save_image(first_image_no) + if last_image_no != first_image_no: + #self.wait_save_image( last_image_no, timeout = total_time+60, show_intermediates = True ) + self.wait_all_images( timeout = total_time+60, show_intermediates = True ) + else: + if not self.omega_hwobj.is_ready(): + self.omega_hwobj.wait_ready( timeout= total_time + 5 ) + + #self.logger.info(" wait_collection_done last image found" ) # doesnt make much sense when user aborts collection + for motorname in self.scan_move_motor_names: + self.logger.info(" Motor %s position = %.2f" % ( motorname, self.scan_motors_hwobj[motorname].get_value() ) ) + + # Wait for omega to stop moving, it continues further than necessary + if not self.aborted_by_user: + if self.omega_hwobj.is_ready(): self.omega_hwobj.wait_ready(timeout=40) + # Wait for any other motors to stop moving + for motorname in self.scan_move_motor_names: + if not self.scan_motors_hwobj[motorname].is_ready(): + self.scan_motors_hwobj[motorname].wait_ready(timeout=40) + # Make sure the detector is ready (in stand by and not moving) + self.detector_hwobj.wait_ready() + + def wait_save_image(self, frame_number, timeout=600, show_intermediates = False): + + full_path = self.get_image_file_name( frame_number ) + intermediate_time_step = 0.1 + + start_wait = time.time() + + self.logger.debug(" waiting for image on disk: %s with timeout %.2f" % ( full_path, timeout ) ) + + while not os.path.exists(full_path) and not self.aborted_by_user: + # TODO: review next line for NFTS related issues. + if (time.time() - start_wait) > timeout: + self.logger.debug(" giving up waiting for image") + cam_state = self.detector_hwobj.chan_cam_state.get_value() + acq_status = self.detector_hwobj.chan_acq_status.get_value() + fault_error = self.detector_hwobj.chan_acq_status_fault_error.get_value() + self.detector_hwobj.get_saving_statistics() + msg = "cam_state = {}, acq_status = {}, fault_error = {}".format( + cam_state, acq_status, fault_error) + self.user_logger.error("Incomplete data collection") + self.user_logger.error(msg) + + self.data_collection_failed( RuntimeError(msg), msg ) + #return False + #self.logger.debug("self.aborted_by_user %s" % str(self.aborted_by_user) ) + time.sleep( intermediate_time_step ) + if show_intermediates: + intermediate_image_number = int( + (time.time() - start_wait) / + self.current_dc_parameters['oscillation_sequence'][0]['exposure_time'] + ) + intermediate_image = self.get_image_file_name( intermediate_image_number ) + if intermediate_image_number < frame_number: + #self.logger.debug(" waiting for image on disk: %s" % intermediate_image) + while not os.path.exists(intermediate_image) and not self.aborted_by_user: + time.sleep(0.01) + self.image_tracking_hwobj.load_image(intermediate_image) + + if os.path.exists(full_path): self.image_tracking_hwobj.load_image(full_path) + self.detector_hwobj.get_saving_statistics() + + # self.last_saved_image = fullpath + + # generate thumbnails + fileinfo = self.current_dc_parameters['fileinfo'] + template = fileinfo['template'] + filename = template % frame_number + archive_dir = fileinfo['archive_directory'] + self.check_directory(archive_dir) + + jpeg_filename = os.path.splitext(filename)[0] + ".jpeg" + thumb_filename = os.path.splitext(filename)[0] + ".thumb.jpeg" + + thumb_fullpath = os.path.join(archive_dir, thumb_filename) + jpeg_fullpath = os.path.join(archive_dir, jpeg_filename) + + self.logger.debug( + " creating thumbnails for %s in: %s and %s" % + (full_path, jpeg_fullpath, thumb_fullpath)) + cmd = "adxv -sa -jpeg_scale 0.4 %s %s" % (full_path, jpeg_fullpath) + os.system(cmd) + cmd = "adxv -sa -jpeg_scale 0.1 %s %s" % (full_path, thumb_fullpath) + os.system(cmd) + + self.logger.debug(" writing thumbnails info in LIMS") + self.store_image_in_lims(frame_number) + + if not self.aborted_by_user: self.logger.debug(" Found image on disk: %s" % full_path) + + return True + + + def wait_all_images(self, timeout=600, show_intermediates = False): + + intermediate_time_step = 0.1 + collect_dir = self.current_dc_parameters['fileinfo']['directory'] + file_template = self.current_dc_parameters['fileinfo']['template'] + glob_file_template = file_template.replace('%04d','*') + number_of_images = self.current_dc_parameters['oscillation_sequence'][0]['number_of_images'] + + start_wait = time.time() + + self.logger.debug(" waiting for %d images with pattern %s with timeout %.2f" % \ + ( number_of_images, os.path.join(collect_dir,glob_file_template), timeout ) + ) + + while len(glob.glob(os.path.join(collect_dir,glob_file_template) )) < number_of_images \ + and not self.aborted_by_user: + # TODO: review next line for NFTS related issues. + if (time.time() - start_wait) > timeout: + self.logger.debug(" giving up waiting for image") + cam_state = self.detector_hwobj.chan_cam_state.get_value() + acq_status = self.detector_hwobj.chan_acq_status.get_value() + fault_error = self.detector_hwobj.chan_acq_status_fault_error.get_value() + self.detector_hwobj.get_saving_statistics() + msg = "cam_state = {}, acq_status = {}, fault_error = {}".format( + cam_state, acq_status, fault_error) + self.user_logger.error("Incomplete data collection") + self.user_logger.error(msg) + + self.data_collection_failed( RuntimeError(msg), msg ) + #return False + #self.logger.debug("self.aborted_by_user %s" % str(self.aborted_by_user) ) + time.sleep( intermediate_time_step ) + if show_intermediates: + intermediate_image_number = int( + (time.time() - start_wait) / + self.current_dc_parameters['oscillation_sequence'][0]['exposure_time'] + ) + intermediate_image = self.get_image_file_name( intermediate_image_number ) + if intermediate_image_number < number_of_images: + #self.logger.debug(" waiting for image on disk: %s" % intermediate_image) + while not os.path.exists(intermediate_image) and not self.aborted_by_user: + time.sleep(0.01) + self.image_tracking_hwobj.load_image(intermediate_image) + + full_path = self.get_image_file_name( number_of_images ) + if os.path.exists(full_path): self.image_tracking_hwobj.load_image(full_path) + self.detector_hwobj.get_saving_statistics() + + # generate thumbnails + fileinfo = self.current_dc_parameters['fileinfo'] + filename = file_template % number_of_images + archive_dir = self.current_dc_parameters['fileinfo']['archive_directory'] + self.check_directory(archive_dir) + + jpeg_filename = os.path.splitext(filename)[0] + ".jpeg" + thumb_filename = os.path.splitext(filename)[0] + ".thumb.jpeg" + + thumb_fullpath = os.path.join(archive_dir, thumb_filename) + jpeg_fullpath = os.path.join(archive_dir, jpeg_filename) + + self.logger.debug( + " creating thumbnails for %s in: %s and %s" % + (full_path, jpeg_fullpath, thumb_fullpath)) + cmd = "adxv -sa -jpeg_scale 0.4 %s %s" % (full_path, jpeg_fullpath) + os.system(cmd) + cmd = "adxv -sa -jpeg_scale 0.1 %s %s" % (full_path, thumb_fullpath) + os.system(cmd) + + self.logger.debug(" writing thumbnails info in LIMS") + self.store_image_in_lims( number_of_images ) + + if not self.aborted_by_user: self.logger.debug(" Found image on disk: %s" % full_path) + + return True + + def get_image_file_name( self, frame_number ): + fileinfo = self.current_dc_parameters['fileinfo'] + basedir = fileinfo['directory'] + template = fileinfo['template'] + + filename = template % frame_number + full_path = os.path.join(basedir, filename) + + return full_path + + def check_shutters(self): + + # Shutters ready: 1, 1, 1, 1 + + # fast shutter closed: State = 1 + # slow shutter is close: State = 0 + # photon shutter is close: State = 0 + # front end is close: State = 0 + fast_shutter = self.fastshut_hwobj.get_state() + slow_shutter = self.slowshut_hwobj.get_state() + photon_shutter = self.photonshut_hwobj.get_state() + front_end = self.frontend_hwobj.get_state() + + shutters = ['fast', 'slow', 'photon', 'front-end'] + states = [fast_shutter, slow_shutter, photon_shutter, front_end] + + failed = [s for s, state in zip(shutters, states) if not state] + + self.logger.debug("fast shutter state is: %s" % fast_shutter) + self.logger.debug("slow shutter state is: %s" % slow_shutter) + self.logger.debug("photon shutter state is: %s" % photon_shutter) + self.logger.debug("front_end state is: %s" % front_end) + + return all([fast_shutter, slow_shutter, photon_shutter, front_end]), failed + + def get_image_headers(self): + headers = [] + return headers + + def data_collection_cleanup(self): + # this is called from AbstractCollect.do_collect, so it is always called and will be the last step in the data collection + + self.logger.debug("XalocCollect data_collection_cleanup started") + + # Not sure what the following line does, does it remove any errors?? + if self.detector_hwobj.get_cam_state() == 'ERROR': self.detector_hwobj.stop_collection() + + self.logger.debug("XalocCollect Unconfiguring the NI") + self.unconfigure_ni() + + self.logger.info('Initial velocity %s' % self.scan_init_velocities) + try: + self.omega_hwobj.stop() + self.omega_hwobj.set_velocity(60) + #if self.omega_init_vel != None: # Sometimes, data collections fails before the initial velocities are set, eg when supervisor or diff DS are in alarm + #self.logger.info(' Setting velocity of motor omega') + #self.logger.info(' to initial velocity %.6f' % self.omega_init_vel ) + #self.omega_hwobj.set_velocity( self.omega_init_vel ) + except: + #self.logger.info(' Setting velocity of motor omega to %.1f failed' % self.omega_init_vel) + self.logger.info(' Setting velocity of motor omega to 60 deg/secs failed') + + for motorname in self.scan_move_motor_names: + self.logger.info(' Setting velocity of motor %s' % motorname ) + self.logger.info(' to initial velocity %.6f' % self.scan_init_velocities[motorname] ) + #self._motor_persistently_set_velocity( self.scan_motors_hwobj[motorname], self.scan_init_velocities[motorname] ) + self.scan_motors_hwobj[motorname].set_velocity( self.scan_init_velocities[motorname] ) + + try: + #Move omega to initial position to speed up collection process + #if self.omega_init_pos != None: # Sometiemes collection fails before omega_init_pos is set, no need to move in those cases + #self.omega_hwobj.set_value( self.omega_init_pos ) + if self.current_dc_parameters['experiment_type'] in ['OSC','Helical']: + self.logger.debug("Cleanup: moving omega to zero") + self.omega_hwobj.set_value(0) + except: + self.logger.debug("Omega needs to be stopped before restoring initial position, will try this now") + self.omega_hwobj.stop() + self.omega_hwobj.set_velocity( self.omega_init_vel ) + #self.omega_hwobj.set_value(self.omega_init_pos) + self.omega_hwobj.set_value( 0 ) + + self.scan_delete_motor_data() + self.fastshut_hwobj.close() # RB: not sure if it closes when unconfiguring it, just in case + + self._collecting = False + self.mxcube_sardanascan_running = False + self.aborted_by_user = False + + self.remove_symbolic_link() + self.logger.debug("Xaloc data_collection_cleanup finished") + + def check_directory(self, basedir): + if not os.path.exists(basedir): + try: + os.makedirs(basedir) + except OSError as e: + import errno + if e.errno != errno.EEXIST: + self.user_logger.error('Directories cannot be made, are the lockdown settings correct?') + self.user_logger.error('Directories cannot be made, are the lockdown settings correct?') + self.data_collection_failed( e, str(e) ) + + def collect_finished(self, green): + self.user_logger.info("Data collection finished") + + def go_to_collect(self, timeout=180): + self.wait_supervisor_ready(timeout=timeout) + self.logger.debug("Sending supervisor to collect phase") + self.supervisor_hwobj.go_collect() + + gevent.sleep(0.5) + + t0 = time.time() + while True: + super_state = self.supervisor_hwobj.get_state() + #super_state2 = self.supervisor_hwobj.current_state + + #self.logger.debug("Supervisor get_state() is %s" % super_state) + #self.logger.debug("Supervisor current current_state is %s" % super_state2) + #TODO: review, sometimes get_current_phase returns None + try: + cphase = self.supervisor_hwobj.get_current_phase().upper() + #self.logger.debug("Supervisor current phase is %s" % cphase) + except: + cphase = None + + if super_state == DevState.ON and cphase == "COLLECT": + break + if time.time() - t0 > timeout: + msg = "Timeout sending supervisor to collect phase" + self.logger.debug(msg) + self.data_collection_failed( RuntimeError(msg), msg ) + if self.aborted_by_user: + msg = "Collection aborted by user" + self.logger.debug(msg) + self.data_collection_failed( Exception(msg), msg ) + gevent.sleep(0.5) + + self.logger.debug("New supervisor phase is %s (Collect phase was requested)" % cphase) + self._collecting = True + + return self.is_collect_phase() + + def is_collect_phase(self): + self.logger.debug("In is_collect_phase method") + try: + return (self.supervisor_hwobj.get_current_phase().upper() == "COLLECT" and self._collecting == True ) # RB added the self._collecting, check if it works + #return self.supervisor_hwobj.get_current_phase().upper() == "COLLECT" + except Exception as e: + msg = "Cannot return current phase from supervisor. Please, restart MXCuBE." + self.user_logger.error(msg) + self.data_collection_failed( e, msg ) + + def go_to_sampleview(self, timeout=180): + self.wait_supervisor_ready() + self.logger.debug("Sending supervisor to sample view phase") + self.close_fast_shutter() + #if not self.supervisor_hwobj.is_fast_shutter_in_collect_position(): + self.close_safety_shutter() + + self.supervisor_hwobj.go_sample_view() + + gevent.sleep(0.5) + + t0 = time.time() + while True: + #TODO: review, some calls return None for get_current_phase() + try: + super_state = self.supervisor_hwobj.get_state() + cphase = self.supervisor_hwobj.get_current_phase().upper() + except: + super_state = cphase = None + if super_state != DevState.MOVING and cphase == "SAMPLE": + break + if time.time() - t0 > timeout: + self.logger.debug("Timeout sending supervisor to sample view phase") + break + gevent.sleep(0.5) + + self.logger.debug("New supervisor phase is %s" % cphase) + + return self.is_sampleview_phase() + + def is_sampleview_phase(self): + return self.supervisor_hwobj.get_current_phase().upper() == "SAMPLE" + + def wait_supervisor_ready(self, timeout=30): + self.logger.debug("Waiting to supervisor ready") + + gevent.sleep(0.5) + + t0 = time.time() + while True: + super_state = self.supervisor_hwobj.get_state() + self.logger.debug("Supervisor state is %s" % super_state) + if super_state == DevState.ON: + break + elif super_state == None: + self.logger.debug("Supervisor state is None, probably a temporary problem") + #break + if time.time() - t0 > timeout: + msg = "Timeout waiting for supervisor ready, call your LC" + self.user_logger.error(msg) + self.data_collection_failed( RuntimeError("Supervisor cannot be operated (state %s)" % super_state), msg) + break + gevent.sleep(0.5) + gevent.sleep(1) + + + def configure_ni(self, start_scan_pos, scan_total_dist, xaloc_scan_motor_name, + override_motor_acceleration): + """ + Sets up the ni660 for triggering detector and fast shutter + the current position of the xaloc_scan_motor_name is used to calculate trigger positions + The motor should be positioned correctly to + - leave sufficient distance to accelerate + - open the fast shutter + + """ + fast_shutter_delay_time = self.fastshut_hwobj.get_shutter_delay_sec() + self.logger.debug( + "Configuring NI660 with pars %.5f %.4f %.4f 0 1 %s %.4f" % + (fast_shutter_delay_time, start_scan_pos, scan_total_dist, + xaloc_scan_motor_name, override_motor_acceleration) + ) + + self.cmd_ni_conf( + fast_shutter_delay_time, + start_scan_pos, # motor scan start position + scan_total_dist, # distance covered by the scan + 0, # trigger_low distance + 1, # trigger count + xaloc_scan_motor_name, # for now either omega or omegax + override_motor_acceleration, # if acceleration is not correct in sardana + wait = True + ) + + def unconfigure_ni(self): + self.cmd_ni_unconf( wait = True ) + # END of lines for ni660 scans + # + # + + + def open_safety_shutter(self): + """ implements prepare_shutters in collect macro """ + + # prepare ALL shutters + + if self.fastshut_hwobj.get_state() != 0: + self.fastshut_hwobj.close() + + if self.slowshut_hwobj.get_state() != 1: + self.slowshut_hwobj.open() + + if self.photonshut_hwobj.get_state() != 1: + self.photonshut_hwobj.open() + + if self.frontend_hwobj.get_state() != 0: + self.frontend_hwobj.open() + + def open_detector_cover(self): + self.supervisor_hwobj.open_detector_cover() + + def open_fast_shutter_for_internal_trigger(self): + # self.fastshut_hwobj.open() + # this function is empty for Xaloc. we are not opening the fast shutter. + # on the contrary open_safety_shutter (equivalent to prepare_shutters in + # original collect macro will first close the fast shutter and open the + # other three + if self.is_collect_phase(): + self.fastshut_hwobj.open() + + def close_fast_shutter(self): + self.fastshut_hwobj.cmd_out() + + def close_safety_shutter(self): + # we will not close safety shutter during collections + pass + + def close_detector_cover(self): + # we will not close detector cover during collections + # self.supervisor.close_detector_cover() + pass + + def scan_delete_motor_data(self): + self.scan_move_motor_names = [] + self.scan_velocities = {} + self.scan_end_positions = {} + self.scan_start_positions = {} + self.scan_init_positions = {} + + def scan_delete_motor_data(self): + self.scan_move_motor_names = [] + self.scan_velocities = {} + self.scan_end_positions = {} + self.scan_start_positions = {} + self.scan_init_positions = {} + + def set_helical_pos(self, arg): + """ + Descript. : 8 floats describe + p1AlignmY, p1AlignmZ, p1CentrX, p1CentrY + p2AlignmY, p2AlignmZ, p2CentrX, p2CentrY + At XALOC, the phiz motor is not moved + """ + self.logger.info('Setting helical motor positions') + self.logger.info('Helical motor positions %s' % str(arg)) + try: + for motorname in self.scan_all_motor_names: # phiy (omegax), phiz (omegaz), sampx (centx), sampy (centy) + if arg["1"][motorname] != None: self.scan_start_positions[motorname] = arg["1"][motorname] + else: self.logger.info('Helical motor %s not added, position is None' % arg["1"][motorname]) + if arg["2"][motorname] != None: self.scan_end_positions[motorname] = arg["2"][motorname] + else: self.logger.info('Helical motor %s not added, position is None' % arg["2"][motorname]) + except Exception as e : + self.logger.error('FAILED TO SET HELICAL MOTOR POSITIONS') + self.data_collection_failed( e, "Cannot interpret helical motor start/end positions") + + def set_scan_move_motors(self, scan_start_pos, scan_end_pos, cutoff=0.005): #cutoff in microns + self.logger.info(' Checking which motors should move for the helical data collection') + for motorname in self.scan_all_motor_names: + self.logger.info(' Motor : %s' % motorname) + self.logger.info(' Start pos: %.4f' % scan_start_pos[motorname]) + self.logger.info(' End pos : %.4f' % scan_end_pos[motorname]) + self.logger.info(' Diff pos : %.4f' % math.fabs(scan_start_pos[motorname] - scan_end_pos[motorname])) + if math.fabs(scan_start_pos[motorname] - scan_end_pos[motorname]) > cutoff and scan_start_pos[motorname] != None and scan_end_pos[motorname] != None: + self.logger.info(' Add helical motor %s' % motorname) + self.scan_move_motor_names.append(motorname) + + def calculate_scan_velocities(self, scan_start_pos, scan_end_pos, total_collection_time): + self.logger.info(' Calculating the velocities for the helical data collection') + self.logger.info(' Calculating the required velocities for the helical motors') + scan_velocities = {} + for motorname in self.scan_move_motor_names: + self.logger.info(' Motor : %s' % motorname) + self.logger.info(' Start pos: %.4f' % scan_start_pos[motorname]) + self.logger.info(' End pos : %.4f' % scan_end_pos[motorname]) + scan_velocities[motorname] = math.fabs ( scan_start_pos[motorname] - scan_end_pos[motorname] ) / total_collection_time + self.logger.info(' Velocity : %.7f' % scan_velocities[motorname]) + + return scan_velocities + + def check_scan_velocities(self, scan_velocities): + self.logger.info(' Checking the velocities for the helical data collection') + scan_motor_velo_keys = scan_velocities.keys() + self.logger.info(' Helical motor list: %s' % scan_motor_velo_keys ) + scan_motor_too_fast = [] # list of motors that cannot go fast enough for the proposed scan + scan_motor_too_slow = [] # list of motors that cannot go slow enough for the proposed scan + for motorname in scan_motor_velo_keys: + self.logger.info(' %7s velocity : %.4f' % (motorname, scan_velocities[motorname]) ) + if scan_velocities[motorname] < self.scan_motors_min_velocity[motorname]: + scan_motor_too_slow.append(motorname) + elif scan_velocities[motorname] > self.scan_motors_max_velocity[motorname]: + scan_motor_too_fast.append(motorname) + + for motorname in scan_motor_too_fast: + self.logger.error('Helical collection error: Stop data collection cause %s cant go fast enough. TIP reduce the range or increase the total data collection time' % motorname) + self.user_logger.error('Helical collection error: Stop data collection cause %s cant go fast enough.' % motorname) + self.user_logger.error(' TIP reduce the distance between starting and ending points, or increase the total data collection time' ) + for motorname in scan_motor_too_slow: + self.logger.error('stop data collection cause %s cant go slow enough. TIP increase the range or reduce the total data collection time' % motorname) + self.user_logger.error('stop data collection cause %s cant go slow enough.' % motorname) + self.user_logger.error(' TIP increase the distance between starting and ending points, or reduce the total data collection time') + + return len(scan_motor_too_fast)+len(scan_motor_too_slow) + + def set_mesh_scan_parameters(self, num_lines, total_nb_frames, mesh_center_param, mesh_range_param): + """ + sets the mesh scan parameters : + - vertcal range + - horizontal range + - nb lines + - nb frames per line + - invert direction (boolean) # NOT YET DONE + """ + + + # num_lines are the number of vertical lines + self.mesh_num_lines = num_lines + self.mesh_total_nb_frames = total_nb_frames + # mesh_range is a list of two values in fast en slow direction: the range is actually the total interval! + self.mesh_range = mesh_range_param + # mesh_center is a dictionary holding centered positions of motors + self.mesh_center = mesh_center_param + self.logger.debug( "mesh_num_lines : %s" % self.mesh_num_lines ) + self.logger.debug( "mesh_total_nb_frames : %s" % self.mesh_total_nb_frames ) + self.logger.debug( "mesh_range : %s" % self.mesh_range ) + self.logger.debug( "mesh_center : %s" % self.mesh_center ) + + + def setMeshScanParameters(self, osc_seq, mesh_mxcube_horizontal_motor_name, mesh_mxcube_vertical_motor_name, mesh_center, mesh_range): + """ + Calculates velocity, starting and end position of the phiy (omegax) motor for each horizontal line scan + the step size for the vertical direction + + + mesh_scan_dict['fast_motor_start_pos'], + mesh_scan_dict['fast_motor_final_pos'], + mesh_scan_dict['fast_motor_nr_images'], + mesh_xaloc_slow_motor_name, + mesh_scan_dict['slow_motor_start_pos'], + mesh_scan_dict['slow_motor_final_pos'], + mesh_scan_dict['slow_motor_nr_images'], +./hardware_objects.xml/mini-diff.xml: {"fast": (1, 0), "slow": (0, -1)} + + + """ + + #TODO: CHECK IF THE SPEED OF THE FAST MOTOR IS NOT TOO FAST! + + # mesh_center is a Centering_Point, which fails to work as a dictionary, following lines needed + if not type(mesh_center) is dict: + mesh_center = mesh_center.as_dict() + #mesh_step_x = mesh_range[0] / float(self.mesh_num_lines) + #mesh_step_y = mesh_range[1] / float(self.mesh_total_nb_frames) / float(self.mesh_num_lines) + + beam_size = self.get_beam_size() # TODO get beam size + self.logger.debug('\t beam size: %s' % str(beam_size)) + + slow_mxcube_motor_name = mesh_mxcube_vertical_motor_name + fast_mxcube_motor_name = mesh_mxcube_horizontal_motor_name + slow_motor_nr_images = self.mesh_num_lines + fast_motor_nr_images = self.mesh_total_nb_frames / self.mesh_num_lines + self.mesh_slow_index = self.mesh_vertical_index + self.mesh_fast_index = self.mesh_horizontal_index + + if self.mesh_num_lines == self.mesh_total_nb_frames: # vertical scan + slow_mxcube_motor_name = mesh_mxcube_horizontal_motor_name + fast_mxcube_motor_name = mesh_mxcube_vertical_motor_name + self.mesh_fast_index = self.mesh_vertical_index + self.mesh_slow_index = self.mesh_horizontal_index + dummy = slow_motor_nr_images + slow_motor_nr_images = fast_motor_nr_images + fast_motor_nr_images = dummy + + self.logger.debug('setMeshScanParameters') + slow_index = self.mesh_slow_index + fast_index = self.mesh_fast_index + + + self.logger.debug('\t mesh_center: %s' % str(mesh_center)) + self.logger.debug('\t mesh_range: %s' % str(mesh_range)) + self.logger.debug('\t fast_index %s' % ( fast_index) ) + self.logger.debug('\t slow_index %s' % ( slow_index) ) + + #TODO: index 0 is fast for mxcube?? Is this configured somewhere? + self.scan_start_positions[ fast_mxcube_motor_name ] = \ + mesh_center [ fast_mxcube_motor_name ] - ( mesh_range[fast_index] / 2.0 ) - ( beam_size[fast_index] / 2.0 ) + self.scan_end_positions[fast_mxcube_motor_name] = \ + self.scan_start_positions[fast_mxcube_motor_name] + mesh_range[fast_index] + beam_size[fast_index] + self.scan_start_positions[slow_mxcube_motor_name] = \ + mesh_center [ slow_mxcube_motor_name ] - ( mesh_range[slow_index] / 2.0 ) + self.scan_end_positions[slow_mxcube_motor_name] = \ + self.scan_start_positions[slow_mxcube_motor_name] + mesh_range[slow_index] + + self.logger.debug('\t slow_mxcube_motor_name: %s' % slow_mxcube_motor_name ) + self.logger.debug('\t fast_mxcube_motor_name: %s' % fast_mxcube_motor_name ) + + self.logger.debug('\t scan_start_positions: %s' % str(self.scan_start_positions)) + self.logger.debug('\t scan_end_positions: %s' % str(self.scan_end_positions)) + + self.logger.debug('\t fast_motor_nr_images: %s' % str( fast_motor_nr_images ) ) + self.logger.debug('\t slow_motor_nr_images: %s' % str( slow_motor_nr_images ) ) + + return slow_mxcube_motor_name, fast_mxcube_motor_name, fast_motor_nr_images, slow_motor_nr_images + + @task + def _take_crystal_snapshot(self, filename): + """ + Descript. : + """ + if not self.is_sampleview_phase(): + self.go_to_sampleview() + + #self.graphics_manager_hwobj.save_scene_snapshot(filename) + HWR.beamline.sample_view.save_scene_snapshot(filename) + self.logger.debug("Crystal snapshot saved (%s)" % filename) + + def set_energy(self, value): + """ + Descript. : This is Synchronous to be able to calculate the resolution @ Xaloc + """ + # program energy + # prepare detector for diffraction + #self.user_logger.warning("Setting beamline energy it can take a while, please be patient") + self.energy_hwobj.move_energy(value) + self.energy_hwobj.wait_move_energy_done() + + def set_wavelength(self, value): + """ + Descript. : + """ + # program energy + # prepare detector for diffraction + self.energy_hwobj.move_wavelength(value) + #self.energy_hwobj.wait_move_wavelength_done() + + def get_energy(self): + return self.energy_hwobj.get_energy() + + def set_transmission(self, value): + """ + Descript. : + """ + self.transmission_hwobj.set_value(value) + + def set_resolution(self, value, energy=None): + """ + Descript. : resolution is a motor in out system + """ + # Current resolution non valid since depends on energy and detector distance!! + #current_resolution = self.resolution_hwobj.get_value() + #self.logger.debug("Current resolution is %s, moving to %s" % (current_resolution, value)) + self.logger.debug("Moving resolution to %s" % value) + + if energy: + # calculate the detector position to achieve the desired resolution + _det_pos = get_dettaby(value, energy=energy) + # calulate the corresponding resolution + value = get_resolution(_det_pos, energy=energy) + + self.resolution_hwobj.set_value(value) + #self.detector_hwobj.wait_move_distance_done() + + def move_detector(self, value): + self.detector_hwobj.move_distance(value) + + def stop_collect(self): + """ + Stops data collection when interrupted by user + overrides AbstractCollect.stop_collect + + This is called from the queue_entry, from the stop method in the DataCollectionQueueEntry class. + The queue_entry stop method is called from the QueueManager when the user clicks stop + + """ + self.logger.debug("XalocCollect stop_collect, colletion stopped by user") + self.aborted_by_user = True + + # Before killing the process, wait for a line scan to stop. self.aborted_by_user is read in the mesh scan methods to decide to go on or not + self.logger.info(" Wait for line scan to finish ") + start_wait = time.time() + timeout = 100 #TODO set a more educated guess for the timeout, depending on the time needed for the scan + while self.mxcube_sardanascan_running == True and (time.time() - start_wait) < timeout: + time.sleep(0.01) + if (time.time() - start_wait) > timeout: + self.user_logger.error("Timeout waiting for scan to stop. Is the Macroserver ok?") + self.logger.debug(" Line scan finished in %s secs " % ( time.time()-start_wait ) ) + + self.logger.info(" Stopping detector") + self.detector_hwobj.stop_collection() + self.logger.info(" Stopping omega motor") + self.omega_hwobj.stop() + for helmovemotorname in self.scan_move_motor_names: + self.scan_motors_hwobj[helmovemotorname].stop() + + AbstractCollect.stop_collect(self) # this kills the collect job + + @task + def move_motors(self, motor_position_dict): + """ + Descript. : + """ + self.diffractometer_hwobj.move_motors(motor_position_dict) + + def create_file_directories(self): + """ + Method create directories for raw files and processing files. + Directories for xds, mosflm, ednaproc and autoproc + """ + self.create_directories( + self.current_dc_parameters['fileinfo']['directory'], + self.current_dc_parameters['fileinfo']['process_directory'] + ) + + self.remove_symbolic_link() + + try: + os.symlink( + self.current_dc_parameters['fileinfo']['directory'], + self.symbolic_link_image_destination, + ) + except Exception as e: + self.user_logger.error('Cannot create the symlink for the images destination, images will not be copied' ) + self.user_logger.error('It is exists, remove the file/directory %s' % self.symbolic_link_image_destination) + self.data_collection_failed( e, str(e) ) + + # create processing directories for each post process + if self.current_dc_parameters['experiment_type'] in ["OSC","Helical"]: + for proc in ['xds', 'mosflm', 'ednaproc', 'autoproc', 'xia2', 'xia2chem']: + self._create_proc_files_directory(proc) + + def remove_symbolic_link(self): + try: + if os.path.exists(self.symbolic_link_image_destination): + os.remove(self.symbolic_link_image_destination) + except Exception as e: + base_dir_name = os.path.dirname(self.symbolic_link_image_destination) + temp_dir_name = os.path.join( + base_dir_name, + "%s-%s" % (HWR.beamline.session.get_proposal(), datetime.now().strftime("%Y%m%d-%H%M%S")) + ) + self.user_logger.error('Cannot remove the symlink for the images destination' ) + self.user_logger.error('Trying to rename to %s' % + temp_dir_name + ) + os.rename( + self.symbolic_link_image_destination, \ + temp_dir_name + ) + if os.path.exists(self.symbolic_link_image_destination): + self.user_logger.error('Cannot update the symlink for the images destination, images will not be copied' ) + self.user_logger.error('Remove the file/directory %s' % self.symbolic_link_image_destination) + self.data_collection_failed( e, str(e) ) + + + # The following methods are copied to improve error logging, the functionality is the same + def create_directories(self, *args): + """ + Descript. : + """ + for directory in args: + self.logger.debug('Creating directory: %s' % str(directory) ) + try: + os.makedirs(directory) + except OSError as e: + import errno + if e.errno != errno.EEXIST: + self.user_logger.error('Error in making the directories, has the permission lockdown been setup properly?' ) + self.data_collection_failed( e, str(e) ) + + def _create_proc_files_directory(self, proc_name): + + i = 1 + + while True: + _dirname = "%s_%s_%s_%d" % ( + proc_name, + self.current_dc_parameters['fileinfo']['prefix'], + self.current_dc_parameters['fileinfo']['run_number'], + i) + _directory = os.path.join( + self.current_dc_parameters['fileinfo']['process_directory'], + _dirname) + if not os.path.exists(_directory): + break + i += 1 + + try: + self.logger.debug('Creating proc directory: %s' % _directory) + self.create_directories(_directory) + os.system("chmod -R 777 %s" % _directory) + except Exception as e: + msg = "Could not create directory %s, are the file permissions setup correctly?\n%s" % (_directory, str(e)) + self.logger.exception(msg) + self.data_collection_failed( e, msg) + + # save directory names in current_dc_parameters. They will later be used + # by autoprocessing. + key = "%s_dir" % proc_name + self.current_dc_parameters[key] = _directory + self.logger.debug("dc_pars[%s] = %s" % (key, _directory)) + return _directory + + + def get_wavelength(self): + """ + Descript. : + Called to save wavelength in lims + """ + if self.energy_hwobj is not None: + return self.energy_hwobj.get_wavelength() + + def get_detector_distance(self): + """ + Descript. : + Called to save detector_distance in lims + """ + if self.detector_hwobj is not None: + return self.detector_hwobj.get_distance() + + def get_resolution(self): + """ + Descript. : + Called to save resolution in lims + """ + if self.resolution_hwobj is not None: + return self.resolution_hwobj.get_value() + + def get_transmission(self): + """ + Descript. : + Called to save transmission in lims + """ + if self.transmission_hwobj is not None: + return self.transmission_hwobj.get_value() + + def get_undulators_gaps(self): + """ + Descript. : return triplet with gaps. In our case we have one gap, + others are 0 + """ + # TODO + try: + if self.chan_undulator_gap: + und_gaps = self.chan_undulator_gap.get_value() + if type(und_gaps) in (list, tuple): + return und_gaps + else: + return (und_gaps) + except BaseException as e: + self.logger.debug("Get undulator gaps error\n%s" % str(e)) + pass + return {} + + def get_beam_size(self): + """ + Descript. : + """ + if self.beam_info_hwobj is not None: + return self.beam_info_hwobj.get_beam_size() + + def get_slit_gaps(self): + """ + Descript. : + """ + if self.beam_info_hwobj is not None: + return self.beam_info_hwobj.get_slits_gap() + return None, None + + def get_beam_shape(self): + """ + Descript. : + """ + if self.beam_info_hwobj is not None: + return self.beam_info_hwobj.get_beam_shape() + + def get_measured_intensity(self): + """ + Descript. : + """ + if self.flux_hwobj is not None: + return self.flux_hwobj.get_flux() + + def get_machine_current(self): + """ + Descript. : + """ + if self.machine_info_hwobj: + return self.machine_info_hwobj.get_current() + else: + return 0 + + def get_machine_message(self): + """ + Descript. : + """ + if self.machine_info_hwobj: + return self.machine_info_hwobj.get_message() + else: + return '' + # TODO: implement fill mode + def get_machine_fill_mode(self): + """ + Descript. : + """ + if self.machine_info_hwobj: + return "FillMode not/impl" + else: + return '' + + def get_flux(self): + """ + Descript. : + """ + return self.get_measured_intensity() + + def trigger_auto_processing(self, event, frame): + pass + if event == "after": + dc_pars = self.current_dc_parameters + self.autoprocessing_hwobj.trigger_auto_processing(dc_pars) + + # TODO: Copied from EMBL, need to be evaluated + def update_lims_with_workflow(self, workflow_id, grid_snapshot_filename): + """Updates collection with information about workflow + + :param workflow_id: workflow id + :type workflow_id: int + :param grid_snapshot_filename: grid snapshot file path + :type grid_snapshot_filename: string + """ + if self.lims_client_hwobj is not None: + try: + self.current_dc_parameters["workflow_id"] = workflow_id + if grid_snapshot_filename: + self.current_dc_parameters["xtalSnapshotFullPath3"] =\ + grid_snapshot_filename + self.lims_client_hwobj.update_data_collection( + self.current_dc_parameters) + except Exception as e: + logging.getLogger("HWR").error( + "Could not store data collection into ISPyB\n%s" % e) + + def _store_image_in_lims_by_frame_num(self, frame_number): + """Store image in lims + + :param frame: dict with frame parameters + :type frame: dict + :param motor_position_id: position id + :type motor_position_id: int + """ + #self.trigger_auto_processing("image", frame_number) + return self.store_image_in_lims(frame_number) + + def get_value_at_corner(self): + if self.rescorner is not None: + return self.rescorner.get_value() + return None + + def collect_experiment_type(self): + return self.current_dc_parameters["experiment_type"] + +def test_hwo(hwo): + print("Energy: ", hwo.get_energy()) + print("Transmission: ", hwo.get_transmission()) + print("Resolution: ", hwo.get_resolution()) + print("Shutters (ready for collect): ", hwo.check_shutters()) + print("Supervisor(collect phase): ", hwo.is_collect_phase()) + + print("Flux ", hwo.get_flux()) + print("Kappa ", hwo.kappapos_chan.get_value()) + print("Phi ", hwo.phipos_chan.get_value()) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocCryostream.py b/mxcubecore/HardwareObjects/ALBA/XalocCryostream.py new file mode 100644 index 0000000000..bfe5b0badb --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocCryostream.py @@ -0,0 +1,93 @@ +# +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] +Liquid nitrogen shower hardware object + +[Description] +Specific HwObj for the liquid nitrogen pump installed at XALOC to wash the crystal + +[Emitted signals] +- ln2showerIsPumpingChanged +- ln2showerFault + +TODO: when the dewar is empty, the operation is INVALID and the State is FAULT +""" + +import logging +import PyTango +import time + +from taurus.core.tango.enums import DevState + +from mxcubecore import HardwareRepository as HWR +from mxcubecore.BaseHardwareObjects import Device + +__credits__ = ["ALBA Synchrotron"] +__version__ = "3" +__category__ = "General" +__author__ = "Roeland Boer" + +class XalocCryostream(Device): + """ + Specific liquid nitrogen shower HwObj for XALOC beamline. + """ + + def __init__(self, name): + Device.__init__(self, name) + + self.logger = logging.getLogger("HWR.XalocCryostream") + self.userlogger = logging.getLogger("user_level_log") + + self.username = None + self.chn_state = None + self.chn_gas_temp= None + self.state = None + self.gas_temp = None + + def init(self): + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + + self.username = self.get_property("username") + self.chn_gas_temp = self.get_channel_object("gas_temp") + self.chn_state = self.get_channel_object("State") + + self.connect(self.chn_gas_temp, "update", self.gas_temp_changed) + self.connect(self.chn_state, "update", self.state_changed) + + def state_changed(self, value): + """ + value can be DevState.FAULT, DevState.ON + """ + if value is not None: + if self.state != value: + self.state = value + self.emit("stateChanged", (self.state,) ) + if value in [DevState.FAULT]: + self.emit("cryostreamFault", (True,) ) + else: + self.emit("cryostreamFault", (False,) ) + + def gas_temp_changed(self, value): + if value is not None: + if self.gas_temp != value: + self.gas_temp = value + self.emit("gasTempChanged", (self.gas_temp,) ) + diff --git a/mxcubecore/HardwareObjects/ALBA/XalocDigitalZoom.py b/mxcubecore/HardwareObjects/ALBA/XalocDigitalZoom.py new file mode 100755 index 0000000000..43f103a778 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocDigitalZoom.py @@ -0,0 +1,268 @@ +# +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +XalocDigitalZoom + +Hardware Object used to integrate the zoom capabilities of the Bzoom system from +ARINAX using the TANGO layer. + +Signals: +- stateChanged +- predefinedPositionChanged + +""" +from __future__ import print_function +import logging + +from enum import IntEnum, unique + +from mxcubecore.BaseHardwareObjects import Device +from taurus.core.tango.enums import DevState + +__credits__ = ["ALBA Synchrotron"] +__licence__ = "LGPLv3+" +__version__ = "3" +__category__ = "General" + + +@unique +class DigitalZoomState(IntEnum): + """ + Defines valid digital zoom states + """ + + UNKNOWN = 0 + READY = 1 + LOW_LIMIT = 2 + HIGH_LIMIT = 3 + DISABLED = 4 + FAULT = -1 + + +class XalocDigitalZoom(Device): + """Hardware object used to control the zoom capabilities.""" + + STATE = DigitalZoomState + + def __init__(self, name): + """ Define variables """ + Device.__init__(self, name) + self.logger = logging.getLogger("HWR.XalocDigitalZoom") + self.user_level_log = logging.getLogger("user_level_log") + self.chan_state = None + self.chan_labels = None + self.chan_blight = None + + self.current_position = 0 + self.current_state = None + + def init(self): + """ Initialize variables """ + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + # TODO: This is not an IOR anymore + self.chan_pos = self.get_channel_object("position") + self.chan_state = self.get_channel_object("state") + # TODO: labels must be harcoded or read as a property + # self.chan_labels = self.get_channel_object("labels") + # TODO: This has to be calibrated with zoom values in the [0,1] range + # self.chan_blight = self.get_channel_object('blight') + + self.chan_pos.connect_signal("update", self.position_changed) + self.chan_state.connect_signal("update", self.state_changed) + + self.current_position = self.get_value() + self.logger.debug('Initial Digital Zoom Position: %s',self.get_value()) + self.current_state = self.get_state() + self.set_name("BZoom") + + def get_predefined_positions_list(self): + """ + It returns the corresponding to the zoom positions. In our case, + ['1', '2', ..., 'n']. This values should be gathered from the Arinax server + + :return: [str,] + + """ + return [str(i) for i in range(1, 8)] + + def move_to_position(self, position): + """ + Move to one of the predefined positions defined in the predefined positions + list. In this case, position names correspont to zoom values and only a + casting to int is required. + + :param position: string value indicating the zoom position. + :return: None + + """ + self.logger.debug("Moving digital zoom to position %s" % position) + self.chan_pos.set_value(int(position)) + + def get_limits(self): + """ + Get zoom limits (i.e. the position name corresponding to the maximum and + minimum values). + + Returns: str, str + + """ + _min = self.get_predefined_positions_list()[0] + _max = self.get_predefined_positions_list()[-1] + return _min, _max + + def get_state(self): + """ + Get the Digital Zoom state (enum) mapping from current Tango state. + + Returns: DigitalZoomState + + # TODO: servers returns always UNKNWON + # TODO: Review type and values returned by Arinax server + + """ + + state = self.chan_state.get_value() + curr_pos = self.get_value() + if state == DevState.ON: + return self.STATE.READY + elif curr_pos == self.get_limits()[0]: + return self.STATE.LOW_LIMIT + elif curr_pos == self.get_limits()[-1]: + return self.STATE.HIGH_LIMIT + if state == DevState.UNKNOWN: + # TODO: Bug in Arinax server: always in UNKNOWN + return self.STATE.READY + # return self.STATE.UNKNOWN + else: + return self.STATE.FAULT + + def get_value(self): + """ + Get the position index from the server. + + Returns: int + + """ + return self.chan_pos.get_value() + + def get_current_position_name(self): + """ + Returns the current zoom position name. + + Returns: str + + """ + return str(self.chan_pos.get_value()) + + def state_changed(self, state): + """ + Slot receiving the zoom state changed and emitting the signal + + Args: + state: Zoom Tango State + + Returns: None + + """ + # TODO: Arrives a Tango State, emits DigitalZoom State + # We should use the state received! + state = self.get_state() + + if state != self.current_state: + self.logger.debug( + "State changed: {} -> {})".format(self.current_state, state) + ) + self.current_state = state + self.emit("stateChanged", (state,)) + + def position_changed(self, position): + """ + Slot receiving the zoom position changed and emitting the signal. + Additionally, we could also actuate the backlight intensity here. + + Args: + position: Zoom int position + + Returns: None + + """ + # TODO: Arrives an int, emits string + # We should use the position received. + position = self.get_current_position_name() + + if position != self.current_position: + #self.logger.debug( + #"Zoom changed: {} -> {}".format(self.current_position, position) + #) + self.current_position = position + self.emit("valueChanged", position) + self.emit("predefinedPositionChanged", (position, 0)) + + def is_ready(self): + """ + Returns: Boolean + + """ + # state = self.get_state() + # return state == self.STATE.READY + # TODO: Bug in Arinax server: state is ALWAYS UNKNOWN + return True + + def get_calibration_pixels_per_mm(self): + """ + Returns the pixel size in um for the current zoom level (self.current_position) + """ + x = None + _zoom_lut = {} + _zoom_lut[1] = 0.0000 + _zoom_lut[2] = 0.1810 + _zoom_lut[3] = 0.3620 + _zoom_lut[4] = 0.5430 + #_zoom_lut[5] = 0.9088 + #_zoom_lut[6] = 0.9540 + #_zoom_lut[7] = 1.0000 + # 20230123: XALOC changed the calibration based on motor movements and pin centering on camera + _zoom_lut[5] = 0.9147579 + _zoom_lut[6] = 0.9573539 + _zoom_lut[7] = 1.0051203277009728 + + #x = 2.0040 + (-1.8370 * _zoom_lut[int(self.current_position)]) + if self.current_position != None: + x = 2.784 + (-2.604 * _zoom_lut[int(self.current_position)]) + else: + self.user_level_log.error("No zoom position available, the bzoom camera DS probably needs to be restarted") + #TODO improve calibration. + #self.logger.debug("Getting calibration from zoom hwobj: position (level) {} pix size (um) {}". + #format(self.current_position,x) + #) + return 1000.0/x, 1000.0/x + + def get_calibration_microns_per_pixel(self): + """ + Returns the pixel size in um for the current zoom level (self.current_position) + """ + x,x = self.get_calibration_pixels_per_mm() + return x * 1000.0, x * 1000.0 + + def get_calibration(self): + """ + Maintained for compatibility. Use get_calibration_pixels_per_mm or get_calibration_microns_per_pixel + """ + return self.get_calibration_microns_per_pixel() diff --git a/mxcubecore/HardwareObjects/ALBA/XalocEDNACharacterisation.py b/mxcubecore/HardwareObjects/ALBA/XalocEDNACharacterisation.py new file mode 100644 index 0000000000..0b8ea6375c --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocEDNACharacterisation.py @@ -0,0 +1,465 @@ +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] XalocEDNACharacterisation + +[Description] +Prepare files and launch strategy pipeline (online) to the ALBA cluster + +[Signals] +- None +""" + +from __future__ import print_function + +import os +import time +import subprocess + +import logging + +from mxcubecore import HardwareRepository as HWR +from EDNACharacterisation import EDNACharacterisation +from XSDataMXCuBEv1_3 import XSDataResultMXCuBE +from XSDataCommon import XSDataFile, XSDataString + +from slurm_client.utils import create_edna_yml + +__credits__ = ["ALBA Synchrotron"] +__version__ = "3" +__category__ = "General" + + +class XalocEDNACharacterisation(EDNACharacterisation): + + def __init__(self, name): + EDNACharacterisation.__init__(self, name) + self.logger = logging.getLogger("HWR.XalocEDNACharacterisation") + self.userlogger = logging.getLogger('user_level_log') + self.job = None + self.output_dir = None + self.input_file = None + self.results_file = None + self.cluster = None + + self.use_cluster_queue = None + self.ssh_user = None + self.ssh_host = None + self.secondary_ssh_host = None + self.ssh_bash_script = None + self.ssh_cluster_bash_script = None + self.edna_source_dir = None + + self.last_processed_dc_id = None + self.proceed = None + + def init(self): + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + EDNACharacterisation.init(self) + self.cluster = self.get_object_by_role("cluster") + + self.use_cluster_queue = self.get_property("use_cluster_queue") + self.ssh_user = self.get_property("ssh_user") + self.ssh_host = self.get_property("ssh_host") + self.secondary_ssh_host = self.get_property("secondary_ssh_host") + self.ssh_bash_script = self.get_property("ssh_bash_script") + self.ssh_cluster_bash_script = self.get_property("ssh_cluster_bash_script") + self.edna_source_dir = self.get_property("edna_source_dir") + + self.proceed = False + + self.connect( + HWR.beamline.collect, "collectOscillationFailed", self.collect_failed + ) + self.connect( + HWR.beamline.collect, "collectOscillationStarted", self.collect_started + ) + + def collect_failed(self, owner, state, message, *args): + self.logger.debug( "Collection failed, unsetting event" ) + self.processing_done_event.clear() + self.proceed = False + + def collect_started(self, owner, state, message, *args): + self.logger.debug( "Collection started, enabling characterisation" ) + self.proceed = True + + def prepare_edna_input(self, input_file, output_dir): + # used for strategy calculation (characterization) using data analysis cluster + # Xaloc specific + input_file.process_directory = output_dir + output_dir = XSDataFile(XSDataString(output_dir)) + input_file.setOutputFileDirectory(output_dir) + + #def _run_edna(self, dc_id, input_file, results_file, output_dir): + #return self.run(dc_id, input_file, results_file, output_dir) + + #def run(self, *args): + + #log = logging.getLogger('user_level_log') + #dc_id, input_file, results_file, output_dir = args + #jobname = os.path.basename(os.path.dirname(output_dir)) + + #self.logger.debug("Submitting Job") + #self.logger.debug(" job_name: %s" % jobname) + #self.logger.debug(" input file: %s" % input_file) + #self.logger.debug(" results file: %s" % results_file) + #self.logger.debug(" output directory: %s" % output_dir) + + #self.job = self.cluster.create_strategy_job(dc_id, input_file, output_dir) + #self.cluster.run(self.job) + + #log.info("Characterization Job ID: %s" % self.job.id) + + #self.output_dir = os.path.dirname(input_file) + #self.input_file = os.path.basename(input_file) + ## self.results_file = self.fix_path(results_file) + #self.results_file = results_file + #self.logger.debug("Results file: %s" % self.results_file) + + #state = self.cluster.wait_done(self.job) + + #if state == "COMPLETED": + #log.info("Job completed") + #time.sleep(0.5) + #result = self.get_result() + #else: + #log.info("Job finished without success / state was %s" % + #state) + #result = "" + + #return result + + # TODO: Deprecated + #def fix_path(self, path): + #out_path = path.replace('PROCESS_DATA', 'PROCESS_DATA/RESULTS') + ## dirname = os.path.dirname(path) + ## basename = os.path.basename(path) + ## outpath = os.path.join(dirname,'RESULTS',basename) + #return out_path + + # TODO: Unused?? + def wait_done(self): + + state = None + time.sleep(0.5) + self.logger.debug("Polling for Job state") + + try: + state = self.job.state + self.logger.debug("Job / is %s" % str(state)) + except Exception as e: + self.logger.debug( + "Polling for Job state, exception happened\n%s" % str(e)) + + while state in ["RUNNING", "PENDING"]: + self.logger.debug("Job / is %s" % state) + time.sleep(0.5) + state = self.job.state + + self.logger.debug("Returning %s" % str(state)) + return state + + def get_result(self): + + # To test diffraction plan handling, uncomment the nex line + # self.results_file = "/beamlines/bl13/projects/cycle2018-I/2018002222-ispybtest/20230329/PROCESSED_DATA/manually-mbounted/characterisation_ref-manually-mbounted_run1_89155/EDNAOutput_89155.xml" + self.logger.debug("Characterization Job COMPLETED") + if self.job != None: + self.logger.debug("Status: %s" % self.job.status) + else: + self.logger.debug("Job run through ssh") + self.logger.debug("Results file: %s" % self.results_file) + if os.path.exists(self.results_file): + result = XSDataResultMXCuBE.parseFile(self.results_file) + self.logger.debug("EDNA Result loaded from file (type is %s" % + str(type(result))) + else: + self.logger.debug( + "Cannot find output file, returning empty string.") + result = "" + + return result + + def characterise(self, edna_input): + """ + Args: + input (EDNAInput) EDNA input object + + Returns: + (str) The Characterisation result + """ + if self.proceed and self.collect_obj.current_dc_parameters["status"] != "Failed": + self.processing_done_event.set() + else: + self.processing_done_event.clear() + self.userlogger.error( "Collection failed, not doing the characterisation" ) + return 'NOT DONE' + + self.prepare_input(edna_input) + path = edna_input.process_directory + + # if there is no data collection id, the id will be a random number + # this is to give a unique number to the EDNA input and result files; + # something more clever might be done to give a more significant + # name, if there is no dc id. + try: + dc_id = edna_input.getDataCollectionId().getValue() + except Exception: + dc_id = id(edna_input) + + token = self.generate_new_token() + edna_input.token = XSDataString(token) + + firstImage = None + #for dataSet in edna_input.dataSet: + for dataSet in edna_input.getDataSet(): + for imageFile in dataSet.imageFile: + if imageFile.getPath() is None: + continue + firstImage = imageFile.path.value + break + + listImageName = os.path.basename(firstImage).split("_") + prefix = "_".join(listImageName[:-2]) + run_number = listImageName[-2] + + if hasattr(edna_input, "process_directory"): + edna_directory = os.path.join( + edna_input.process_directory, + "characterisation_%s_run%s_%s" % (prefix, run_number, dc_id ) + ) + os.makedirs(edna_directory) + else: + raise RuntimeError("No process directory specified in edna_input") + + edna_input_file = os.path.join(edna_directory, "EDNAInput_%s.xml" % dc_id) + + self.prepare_edna_input(edna_input, edna_directory) + + try: + edna_input.exportToFile(edna_input_file) + except: + import traceback + self.logger.debug("Problem generating input file:") + self.logger.debug(" %s " % traceback.format_exc()) + + edna_results_file = os.path.join(edna_directory, "EDNAOutput_%s.xml" % dc_id) + + msg = "Starting EDNA using xml file %r", edna_input_file + self.logger.info(msg) + #TODO: ALBA used local version of _run_edna to pass dc_id. + # Not sure why the implemented method is not used, + # self.result = self._run_edna(edna_input_file, edna_results_file, path) + self.result = self._run_edna_xaloc(dc_id, edna_input_file, edna_results_file, edna_directory) + + self.processing_done_event.clear() + return self.result + + def _run_edna_xaloc_cluster(self, dc_id, input_file, results_file, output_dir): + """ + Starts EDNA + Job Submission managed by slurm client. + Note that XalocCluster by default sends the file to SCRATCH + """ + if self.collect_obj.current_dc_parameters["status"] == "Failed": + self.userlogger.error("Collection failed, no characterisation done") + return '' + + msg = "Starting EDNA characterisation using xml file %s" % input_file + self.logger.info(msg) + + jobname = os.path.basename( os.path.dirname(output_dir) ) + + self.logger.debug("Submitting Job") + self.logger.debug(" job_name: %s" % jobname) + self.logger.debug(" input file: %s" % input_file) + self.logger.debug(" results file: %s" % results_file) + self.logger.debug(" output directory: %s" % output_dir) + + self.job = self.cluster.create_strategy_job(dc_id, input_file, output_dir) + self.cluster.run(self.job) + + self.userlogger.info("Characterization Job ID: %s" % self.job.id) + + self.output_dir = os.path.dirname(input_file) + self.input_file = os.path.basename(input_file) + self.results_file = results_file + self.logger.debug("Results file: %s" % self.results_file) + + self.last_processed_dc_id = dc_id + + #state = self.cluster.wait_done(self.job) + results_file_exists = self.wait_results_file(results_file) + + #if state == "COMPLETED": + if results_file_exists: + self.logger.info("Job completed") + time.sleep(0.5) + result = self.get_result() + self.logger.info("HTML in results file %s" % result.getHtmlPage().getPath().getValue() ) + else: + #self.logger.info("Job finished without success / state was %s" % + #state) + self.logger.info("Job did not run properly, no analysis done, check with your LC ") + result = "" + + return result + + def _run_edna_xaloc_ssh(self, dc_id, input_file, results_file, output_dir): + """ + Starts EDNA using ssh protocol, directly to cluster. + """ + if self.collect_obj.current_dc_parameters["status"] == "Failed": + self.logger.error("Collection failed, no characterisation done") + return '' + + msg = "Starting EDNA characterisation using xml file %s" % input_file + self.logger.info(msg) + + jobname = os.path.basename( os.path.dirname(output_dir) ) + + self.logger.debug("Submitting Job") + self.logger.debug(" job_name: %s" % jobname) + self.logger.debug(" input file: %s" % input_file) + self.logger.debug(" results file: %s" % results_file) + self.logger.debug(" output directory: %s" % output_dir) + + _yml_file = create_edna_yml(str(dc_id), + self.cluster.pipelines['strategy']['plugin'], + input_file, + self.ssh_cluster_bash_script, + workarea='SCRATCH', + benchmark=False, + dest=output_dir, + use_scripts_root=False, + xds=None, + configdef=None) + + + + #proc_command = "ssh %s@%s %s %s" % (self.ssh_user, self.ssh_host, self.ssh_bash_script, ssh_parameters) + #self.logger.info( "Executing command: %s" % proc_command ) + #os.system(proc_command) + self.last_processed_dc_id = dc_id + + if self.ssh_host != None and self.ssh_host != '': + ssh_parameters = "%s %s %s %s %s %s %s %s %s %s" % ( + self.ssh_user, + self.secondary_ssh_host, + self.ssh_cluster_bash_script, + self.cluster.pipelines['strategy']['plugin'], + input_file, + results_file, + output_dir, + "SCRATCH", + False, + self.edna_source_dir + ) + proc_command = "%s %s" % (self.ssh_bash_script, ssh_parameters) + self.logger.info( "Executing command: ssh %s@%s %s" % (self.ssh_user, self.ssh_host, proc_command ) ) + subprocess.call(['ssh', '%s@%s' % (self.ssh_user, self.ssh_host), proc_command]) + else: + ssh_parameters = "%s %s %s %s %s %s %s %s" % ( + self.ssh_cluster_bash_script, + self.cluster.pipelines['strategy']['plugin'], + input_file, + results_file, + output_dir, + "LOCAL",# for pcbl1309 + False, + self.edna_source_dir + ) + self.logger.info( "Executing command: ssh %s@%s %s" % (self.ssh_user, self.secondary_ssh_host, ssh_parameters) ) + subprocess.call(['ssh', '%s@%s' % (self.ssh_user, self.secondary_ssh_host), ssh_parameters]) + + #self.logger.info("Characterization Job ID: %s" % job_id) + + self.output_dir = os.path.dirname(input_file) + self.input_file = os.path.basename(input_file) + self.results_file = results_file + self.logger.debug("Results file: %s" % self.results_file) + + results_file_exists = self.wait_results_file(results_file) + if results_file_exists: + result = self.get_result() + else: + self.logger.info("Job did not run properly, no analysis done, check with your LC ") + result = "" + + return result + + def _run_edna_xaloc(self, dc_id, input_file, results_file, output_dir): + self.job = None # reset job name + self.last_processed_dc_id = None + + result = '' + if self.use_cluster_queue: + result = self._run_edna_xaloc_cluster(dc_id, input_file, results_file, output_dir) + else: + result = self._run_edna_xaloc_ssh(dc_id, input_file, results_file, output_dir) + + return result + + def wait_results_file(self, results_file, timeout = 30): + sttime = time.time() + while not os.path.exists(results_file) and \ + time.time() - sttime < timeout: + time.sleep(0.2) + return os.path.exists(results_file) + + def get_html_report(self, edna_result): + """ + Args: + output (EDNAResult) EDNAResult object + + Returns: + (str) The path to the html result report generated by the characterisation + software + + /beamlines/bl13/projects/cycle2023-I/2022086950-acamara-artigas/20230131/PROCESSED_DATA/RESULTS/B1X4/characterisation_ref-B1X4_run1_84450/proc_ 71573656/ + /beegfs/scratch/strategy_ 71573693/EDApplication_20230131-190222/ControlInterfaceToMXCuBEv1_3/SimpleHTML/index.html + """ + html_report = None + + try: + # Chapuza alert! the characterisation is run locally on the cluster, and the path of the html report in the EDNA output xml is also local + # This path is reset within the script that runs the characterisation, after EDNA is done. So we have to wait for the file to appera + # Solution: read directly from cluster beegfs from pcbl1307 + html_report = str( edna_result.getHtmlPage().getPath().getValue() ) + while not os.path.exists(html_report): + time.sleep(0.2) + result = XSDataResultMXCuBE.parseFile(self.results_file) + html_report = str(result.getHtmlPage().getPath().getValue()) + except AttributeError: + logging.getLogger("Cant find html page in edna_result %s" % edna_result) + pass + + return html_report + + +def test_hwo(hwo): + ofile = "/tmp/edna/edna_result" + odir = "/tmp/edna" + test_input_file = "/beamlines/bl13/projects/cycle2018-I/2018012551-bcalisto/" \ + "mx2018012551/DATA/20180131/PROCESS_DATA/" \ + "characterisation_ref-Thrombin-TB-TTI1_A_run1_1/" \ + "EDNAInput_2004391.xml" + result = hwo.run_edna(test_input_file, ofile, odir) + print(result) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocEnergy.py b/mxcubecore/HardwareObjects/ALBA/XalocEnergy.py new file mode 100644 index 0000000000..b065560209 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocEnergy.py @@ -0,0 +1,184 @@ +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] XalocEnergy + +[Description] +HwObj used to configure the beamline energy. + +[Signals] +- energyChanged +""" + +#from __future__ import print_function + +import logging + +from mxcubecore.HardwareObjects.Energy import Energy + +__credits__ = ["ALBA Synchrotron"] +__version__ = "3" +__category__ = "General" + + +class XalocEnergy(Energy): + + def __init__(self, name): + Energy.__init__(self, name) + self.logger = logging.getLogger("HWR.XalocEnergy") + #self.energy_motor = None + self.wavelength_motor = None + self.is_tunable = None + + self.energy_position = None + self.wavelength_position = None + + def init(self): + #Energy.init(self) + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + #self.energy_motor = self.get_object_by_role("energy") + self.wavelength_motor = self.get_object_by_role("wavelength") + + try: + self.energy_motor = self.get_object_by_role("energy") + except KeyError: + logging.getLogger("HWR").warning("Energy: error initializing energy motor") + + try: + self.is_tunable = self.get_property("tunable_energy") + except KeyError: + self.is_tunable = False + logging.getLogger("HWR").warning("Energy: will be set to fixed energy") + + if self.energy_motor is not None: + #self.connect(self.wavelength_motor, "valueChanged", + #self.energy_position_changed) + self.connect(self.energy_motor, "valueChanged", + self.energy_position_changed) + self.energy_motor.connect("stateChanged", self.energyStateChanged) + + + def is_ready(self): + try: + if self.energy_motor is not None: + return self.energy_motor.is_ready() + else: return True + except Exception as e: + logging.getLogger("HWR").warning("Energy error %s" % str(e) ) + return True + + def can_move_energy(self): + #if self.energy_motor is not none: + #return not self.energy_motor.is_moving() + #else: return True + return True + + def get_value(self): + if self.energy_motor is not None: + try: + return self.energy_motor.get_value() + except Exception: + logging.getLogger("HWR").exception( + "EnergyHO: could not read current energy" + ) + return None + return self.default_en + + def get_wavelength(self): + if self.wavelength_motor != None: + self.wavelength_position = self.wavelength_motor.get_value() + return self.wavelength_position + + def update_values(self): + self.energy_position_changed() + + #TODO update resolution. Resolution has a method called energyChanged, which takes a egy but doenst use it + # this calls updateResolution, which also calls update_beam_center, but probably this doesnt affect Xaloc + # as the beam center is taken from Variables just before a collect. Check though... + def energy_position_changed(self, value): + self.energy_position = self.energy_motor.get_value() + self.wavelength_position = self.wavelength_motor.get_value() + if None not in [self.energy_position, self.wavelength_position]: + self.emit('energyChanged', self.energy_position, self.wavelength_position) + self.emit("valueChanged", (self.energy_position,)) + + #def wavelength_position_changed(self, value): + #wavelength_position = value + #energy_position = energy_motor.get_value() + #if None not in [energy_position, wavelength_position]: + #self.emit('energyChanged', energy_position, wavelength_position) + + def move_energy(self, value, timeout=0): + current_egy = self.get_value() + + self.logger.debug("Moving energy to %s. now is %s" % (value, current_egy)) + + if abs(value-current_egy) > self.energy_motor.move_threshold: + self.energy_motor.set_value(value, timeout) + else: + self.logger.debug("Change below threshold. not moved") + + set_value = move_energy + #_set_value = move_energy + + def wait_move_energy_done(self): + self.logger.debug("wait_move_energy_done energ_motor state is %s" % (self.energy_motor.get_state() ) ) + self.energy_motor.wait_ready(timeout = 30) + + def move_wavelength(self, value): + # convert wavelength to energy and move energy + + current_lambda = self.get_wavelength() + kV_from_lambda = 12.398419303652055 / value + self.logger.debug("Requested wavelength change, moving wavelength to %s (E %s). now is %s" % + (value, kV_from_lambda, current_lambda) + ) + + self.move_energy( kV_from_lambda ) + #self.wavelength_motor.set_value(value) + + def wait_move_wavelength_done(self): + self.wavelength_motor.wait_ready() + + def get_energy_limits(self): + return self.energy_motor.get_limits() + + get_limits=get_energy_limits + + def get_wavelength_limits(self): + return self.wavelength_motor.get_limits() + + set_wavelength = move_wavelength + + def stop(self): + self.energy_motor.stop() + self.energy_motor.update_values() + + def energyStateChanged(self, state): + """ + state is a MotorState + state.value[0] retrieves HardwareObjectState from MotorState + """ + self.emit("stateChanged", (state.value[0],)) + +def test_hwo(hwo): + print("Energy is: ", hwo.get_energy()) + print("Wavelength is: ", hwo.get_wavelength()) + print("Energy limits are: ", hwo.get_energy_limits()) + print("Wavelength limits are: ", hwo.get_wavelength_limits()) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocEpsActuator.py b/mxcubecore/HardwareObjects/ALBA/XalocEpsActuator.py new file mode 100644 index 0000000000..6c6463862b --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocEpsActuator.py @@ -0,0 +1,153 @@ +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + + +""" +[Name] XalocEpsActuator + +[Description] +Tango Shutter Hardware Object + +Public Interface: + Commands: + int get_state() + Description: + returns current state + Output: + integer value describing the state + current states correspond to: + 0: out + 1: in + 9: moving + 11: alarm + 13: unknown + 23: fault + + string get_status() + Description: + returns current state as a string that can contain a more + descriptive information about current state + + Output: + status string + + cmd_in() + Executes the command associated to the "In" action + cmd_out() + Executes the command associated to the "Out" action + + [Signals] + stateChanged + +""" + +from __future__ import print_function + +import logging + +from mxcubecore import BaseHardwareObjects + +__credits__ = ["ALBA Synchrotron"] +__version__ = "3" +__category__ = "General" + +STATE_IN, STATE_OUT, STATE_MOVING, STATE_FAULT, STATE_ALARM, STATE_UNKNOWN = \ + (0, 1, 9, 11, 13, 23) + + +class XalocEpsActuator(BaseHardwareObjects.Device): + + states = { + STATE_OUT: "out", + STATE_IN: "in", + STATE_MOVING: "moving", + STATE_FAULT: "fault", + STATE_ALARM: "alarm", + STATE_UNKNOWN: "unknown", + } + + default_state_strings = ["In", "Out"] + + def __init__(self, name): + BaseHardwareObjects.Device.__init__(self, name) + self.logger = logging.getLogger("HWR.XalocEpsActuator") + self.chan_actuator = None + + self.actuator_state = None + self.state_strings = None + + def init(self): + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + self.actuator_state = STATE_UNKNOWN + + try: + self.chan_actuator = self.get_channel_object("actuator") + self.chan_actuator.connect_signal("update", self.state_changed) + except KeyError: + self.logger.warning('Cannot report EPS Actuator State for %s' % self.name()) + + try: + state_string = self.get_property("states") + if state_string is None: + self.state_strings = self.default_state_strings + else: + self.state_strings = state_string.split(",") + except Exception as e: + self.logger.warning("%s" % str(e)) + self.state_strings = self.default_state_strings + + def get_state(self): + self.actuator_state = self.chan_actuator.force_get_value() + return self.actuator_state + + def state_changed(self, value): + self.actuator_state = value + self.logger.debug("State change for actuator %s, new state is %s" % (self.name(), value) ) + self.emit('stateChanged', (self.actuator_state,)) + + def get_user_name(self): + return self.username + + def get_status(self): + """ + """ + state = self.get_state() + + if state in [STATE_OUT, STATE_IN]: + return self.state_strings[state] + elif state in self.states: + return self.states[state] + else: + return "Unknown" + + def open(self): + self.cmd_out() + + def close(self): + self.cmd_in() + + def cmd_in(self): + self.chan_actuator.set_value( STATE_IN ) + + def cmd_out(self): + self.chan_actuator.set_value( STATE_OUT ) + +def test_hwo(hwo): + print("Name is: ", hwo.getUserName()) + print("Shutter state is: ", hwo.get_state()) + print("Shutter status is: ", hwo.get_status()) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocFastShutter.py b/mxcubecore/HardwareObjects/ALBA/XalocFastShutter.py new file mode 100755 index 0000000000..a24a0b6951 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocFastShutter.py @@ -0,0 +1,233 @@ +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] XalocFastShutter + +[Description] +HwObj used to operate the Fast Shutter + +[Signals] +- fastStateChanged +""" + +from __future__ import print_function + +import logging +import time + +from mxcubecore import BaseHardwareObjects +from taurus.core.tango.enums import DevState + + +__credits__ = ["ALBA Synchrotron"] +__version__ = "2.3" +__category__ = "General" + +STATE_OUT, STATE_IN, STATE_MOVING, STATE_FAULT, STATE_ALARM, STATE_UNKNOWN = \ + (0, 1, 9, 11, 13, 23) + + +class XalocFastShutter(BaseHardwareObjects.Device): + """ + Shutter IN: motor position is 0 and IDLE state is High. + Shutter OUT: motor position is 0 and IDLE state is Low. + Shutter Fault: motor position is not 0. + """ + + states = { + STATE_OUT: "out", + STATE_IN: "in", + STATE_MOVING: "moving", + STATE_FAULT: "fault", + STATE_ALARM: "alarm", + STATE_UNKNOWN: "unknown", + } + + default_state_strings = ["Out", "In"] + + def __init__(self, name): + BaseHardwareObjects.Device.__init__(self, name) + self.logger = logging.getLogger("HWR.XalocFastShutter") + self.cmd_ni_start = None + self.cmd_ni_stop = None + + self.chan_actuator = None + self.chan_motor_pos = None + self.chan_motor_state = None + + self.actuator_state = STATE_UNKNOWN + self.actuator_value = None + self.motor_position = None + self.motor_state = None + self.state_strings = None + + self.shutter_delay_time_sec = None + + def init(self): + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + try: + self.shutter_delay_time_sec = self.get_property('shutter_delay_time_sec') + self.cmd_ni_start = self.get_command_object("nistart") + self.cmd_ni_stop = self.get_command_object("nistop") + + self.chan_actuator = self.get_channel_object('actuator') + self.chan_motor_pos = self.get_channel_object('motorposition') + self.chan_motor_state = self.get_channel_object('motorstate') + + self.chan_actuator.connect_signal('update', self.state_changed) + self.chan_motor_pos.connect_signal('update', self.motor_position_changed) + self.chan_motor_state.connect_signal('update', self.motor_state_changed) + except Exception: + self.logger.warning('Error when initilaizing') + + try: + state_string = self.get_property("states") + if state_string is None: + self.state_strings = self.default_state_strings + else: + states = state_string.split(",") + self.state_strings = states[1].strip(), states[0].strip() + except Exception as e: + self.logger.warning("%s" % str(e)) + self.state_strings = self.default_state_strings + + def get_state(self): + if self.actuator_state == STATE_UNKNOWN: + self.actuator_value = self.chan_actuator.get_value() + self.motor_position = self.chan_motor_pos.get_value() + self.motor_state = self.chan_motor_state.get_value() + self.update_state(value) + return self.actuator_state + + def update_state(self, state_unused): + + if None in [self.actuator_value, self.motor_position, self.motor_state]: + act_state = STATE_UNKNOWN + elif self.motor_state == DevState.MOVING: + act_state = STATE_MOVING + elif self.motor_state != DevState.ON or abs(self.motor_position) > 0.01: + act_state = STATE_ALARM + else: + state = self.actuator_value.lower() + + if state == 'high': + act_state = STATE_IN + else: + act_state = STATE_OUT + + if act_state != self.actuator_state: + self.actuator_state = act_state + self.emit_state_changed() + + def state_changed(self, value): + self.actuator_value = value + self.update_state(value) + + def motor_position_changed(self, value): + self.motor_position = value + self.update_state(value) + + def motor_state_changed(self, value): + self.motor_state = value + self.update_state(value) + + def emit_state_changed(self): + self.emit('fastStateChanged', (self.actuator_state,)) + + def get_motor_position(self): + if self.motor_position is None: + self.motor_position = self.chan_motor_pos.get_value() + return self.motor_position + + def get_motor_state(self): + if self.motor_state is None: + self.motor_state = self.chan_motor_state.get_value() + return self.motor_state + + def get_user_name(self): + return self.username + + def get_shutter_delay_sec(self): + return self.shutter_delay_time_sec + + def get_status(self): + state = self.getState() + + if state in [STATE_OUT, STATE_IN]: + return self.state_strings[state] + elif state in self.states: + return self.states[state] + else: + return "Unknown" + + def cmd_in(self): + self.open() + + def cmd_out(self): + self.close() + + def close(self): + self.logger.debug("Closing the fast shutter") + #self.logger.debug("value = %s, state = %s" % + #(self.chan_motor_pos.get_value(), + #self.actuator_state)) + if abs(self.chan_motor_pos.get_value()) > 0.01: + while self.get_motor_state() != DevState.ON: + time.sleep(0.5) + # closed position is 0 + self.chan_motor_pos.set_value(0) + self.set_ttl('High') + + def open(self): + self.logger.debug("Opening the fast shutter") + #self.logger.debug("value = %s, state = %s" % + #(self.chan_motor_pos.get_value(), + #self.actuator_state)) + + if abs(self.chan_motor_pos.get_value()) > 0.01: + self.chan_motor_pos.set_value(0) + self.set_ttl('Low') + + def set_ttl(self, value): + self.cmd_ni_stop() + self.chan_actuator.set_value(value) + self.cmd_ni_start() + + def is_open(self): + if self.actuator_state == STATE_IN: + + return True + else: + return False + + def is_close(self): + if self.actuator_state == STATE_OUT: + return True + else: + return False + + +def test_hwo(hwo): + print("Name is: ", hwo.get_user_name()) + print("Shutter state is: ", hwo.get_state()) + print("Shutter status is: ", hwo.get_status()) + print("Motor position is: ", hwo.get_motor_position()) + print("Motor state is: ", hwo.get_motor_state()) + print("Is shutter open: ", hwo.is_open()) + print("Is shutter close: ", hwo.is_close()) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocFlux.py b/mxcubecore/HardwareObjects/ALBA/XalocFlux.py new file mode 100644 index 0000000000..839203ea73 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocFlux.py @@ -0,0 +1,116 @@ +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] XalocFlux + +[Description] +HwObj used to get the flux + +[Signals] +- None +""" + +from __future__ import print_function + +import logging + +from mxcubecore.HardwareObjects.abstract.AbstractFlux import AbstractFlux +from mxcubecore import HardwareRepository as HWR +#from HardwareRepository.BaseHardwareObjects import Device + +__credits__ = ["ALBA Synchrotron"] +__version__ = "3" +__category__ = "General" + + +class XalocFlux(AbstractFlux): + + def __init__(self, name): + self.logger = logging.getLogger("HWR.XalocFlux") + AbstractFlux.__init__(self, name) + self.current_chn = None + self.transmission_chn = None + self.last_flux_chn = None + self.last_flux_norm_chn = None + self.default_flux = None + + def init(self): + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + self.transmission_chn = self.get_channel_object("transmission") + self.last_flux_chn = self.get_channel_object("last_flux") + self.last_flux_norm_chn = self.get_channel_object("last_flux_norm") + self.default_flux = self.get_property('default_flux') + if self.default_flux == None: + self.default_flux = 1.5E12 + self.logger.debug("Default flux set to %8.3f" % self.default_flux) + + def get_value(self): + return self.get_flux() + + def get_flux(self): + last_flux = self.last_flux_chn.get_value() + try: + if last_flux != None: + if last_flux > 1e7: + return self.get_flux_from_last_measured() * self.get_transmission() + else: + self.logger.debug( "Flux value abnormally low" ) + else: + self.logger.debug( "Flux value is None" ) + + + except Exception as e: + self.logger.error("Cannot read flux\n%s" % str(e)) + #logging.getLogger("user_level_log").error("Cannot read flux\n%s" % str(e)) + + self.logger.debug( "Returning default flux value %8.3f" % self.default_flux ) + + return self.default_flux + + + def get_transmission(self): + """ returns transmission between 0 and 1""" + return self.transmission_chn.get_value() / 100. + + def get_flux_from_last_measured(self): + last_flux_norm = self.last_flux_norm_chn.get_value() + current = HWR.beamline.machine_info.get_mach_current() + self.logger.debug("XalocFlux machine current %s" % current) + + last_current = (last_flux_norm / 250.) * current + return last_current + + def get_dose_rate(self, energy=None): + """ + Get dose rate in kGy/s for a standard crystal at current settings. + Assumes Gaussian beam with beamsize giving teh FWHH in both dimensions. + + :param energy: float Energy for calculation of dose rate, in keV. + :return: float + """ + + # The factor 1.25 converts from the average value over the beamsize + # to an estimated flux density at the peak. + return 1.25 * AbstractFlux.AbstractFlux.get_dose_rate_per_photon_per_mmsq(self, energy=energy) + + +def test_hwo(hwo): + print("Flux = %.4e" % hwo.get_flux()) + print("Last current = %.4e" % hwo.get_last_current()) + print("Transmission = %.2f" % hwo.get_transmission()) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocFrontEnd.py b/mxcubecore/HardwareObjects/ALBA/XalocFrontEnd.py new file mode 100644 index 0000000000..4312e631ee --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocFrontEnd.py @@ -0,0 +1,70 @@ +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] XalocFrontEnd + +[Description] +The XalocFastShutter hardware object is a variation of the XalocEpsActuator +where the command to open/close is done on a different channel than the +reading of the shutter state. + +The interface is otherwise exactly the same as the XalocEpsActuator + +[Signals] +- None +""" + +from __future__ import print_function + +import logging + +from XalocEpsActuator import XalocEpsActuator + +__credits__ = ["ALBA Synchrotron"] +__version__ = "2.3" +__category__ = "General" + + +class XalocFrontEnd(XalocEpsActuator): + def __init__(self, name): + XalocEpsActuator.__init__(self, name) + self.logger = logging.getLogger("HWR.XalocFrontEnd") + self.logger.debug("__init__()") + self.chan_open = None + self.chan_close = None + + def init(self): + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + XalocEpsActuator.init(self) + + self.chan_open = self.get_channel_object('open_command') + self.chan_close = self.get_channel_object('close_command') + + def cmd_out(self): + self.chan_close.set_value(False) + self.chan_open.set_value(True) + + def cmd_in(self): + self.chan_open.set_value(False) + self.chan_close.set_value(True) + +def test_hwo(hwo): + print("Name is: ", hwo.getUserName()) + print("Shutter state is: ", hwo.get_state()) + print("Shutter status is: ", hwo.get_status()) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocFrontLight.py b/mxcubecore/HardwareObjects/ALBA/XalocFrontLight.py new file mode 100755 index 0000000000..0ead1265d0 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocFrontLight.py @@ -0,0 +1,155 @@ +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] XalocFrontLight + +[Description] +HwObj used to control the diffractometer front light. + +[Signals] +- levelChanged +- stateChanged +""" + +#from __future__ import print_function + +import logging + +from mxcubecore.BaseHardwareObjects import Device +from taurus.core.tango.enums import DevState + +__credits__ = ["ALBA Synchrotron"] +__version__ = "3" +__category__ = "General" + + +class XalocFrontLight(Device): + + def __init__(self, *args): + Device.__init__(self, *args) + self.logger = logging.getLogger("HWR.XalocFrontLight") + + self.chan_level = None + self.chan_state = None + + self.limits = [None, None] + + self.state = None + self.dev_server_state = None # state of the device server controlling the light + + self.current_level = None + + self.default_off_threshold = 1 # threshold is 1 click above off value + self.off_threshold = None + + def init(self): + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + self.chan_level = self.get_channel_object("light_level") + self.chan_state = self.get_channel_object("state") + self.off_threshold = self.get_property("off_threshold", self.default_off_threshold) + self.logger.debug("Off_threshold value = %s" % self.off_threshold) + + self.set_name('frontlight') + + limits = self.get_property("limits") + if limits is not None: + lims = limits.split(",") + if len(lims) == 2: + self.limits = map(float, lims) + + self.chan_level.connect_signal("update", self.level_changed) + self.chan_state.connect_signal("update", self.dev_server_state_changed) + + def is_ready(self): + return True + + def level_changed(self, value): + #self.logger.debug("FrontLight level changed, value = %s" % value) + self.current_level = float( value ) + self.update_current_state() + + self.emit('levelChanged', self.current_level) + + def dev_server_state_changed(self, value): + #self.logger.debug("Device server state changed, value = %s" % value) + self.dev_server_state = value + if value != DevState.ON: + self.logger.error("The device server of the front light is not ON") + logging.getLogger('user_level_log').error("The device server of the front light is not ON. Call your LC") + self.update_current_state() + + def update_current_state(self): + #self.logger.debug("FrontLight state is %s, off_threshold = %s, state == DevState.ON %s" % ( str(self.dev_server_state), \ + #str(self.off_threshold), (self.dev_server_state == DevState.ON ) ) + #) + newstate = False + if self.dev_server_state == DevState.ON: + if self.off_threshold is not None: + if self.current_level < 0.9 * self.off_threshold: + newstate = False + else: + newstate = True + else: + newstate = True + elif self.dev_server_state == DevState.OFF: + newstate = False + else: + newstate = False + + if newstate != self.state: + self.state = newstate + self.emit('stateChanged', self.state) + + def get_limits(self): + return self.limits + + def get_state(self): + self.dev_server_state = str(self.chan_state.get_value()).lower() + self.update_current_state() + return self.state + + def get_user_name(self): + return self.username + + def get_level(self): + self.current_level = self.chan_level.get_value() + return self.current_level + + def set_level(self, level): + #self.logger.debug("Setting level in %s to %s" % (self.username, level)) + self.chan_level.set_value(float(level)) + + def set_on(self): + #self.logger.debug("Setting front light on with intensity %s" % str(self.limits[1] ) ) + self.chan_level.set_value( float( self.limits[1] ) ) + + def set_off(self): + #self.logger.debug("Setting front light off") + self.chan_level.set_value( float( self.limits[0] ) ) + + def re_emit_values(self): + self.emit("stateChanged", self.state ) + self.emit("levelChanged", self.current_level ) + + +def test_hwo(hwo): + print("Light control for \"%s\"\n" % hwo.get_user_name()) + print("Level limits are:", hwo.get_limits()) + print("Current level is:", hwo.get_level()) + print("Current state is:", hwo.get_state()) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocISPyBClient.py b/mxcubecore/HardwareObjects/ALBA/XalocISPyBClient.py new file mode 100755 index 0000000000..06fdca51a4 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocISPyBClient.py @@ -0,0 +1,231 @@ +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] XalocISPyBClient + +[Description] +HwObj used to interface the ISPyB database + +[Signals] +- None +""" + +#from __future__ import print_function + +import logging + +from mxcubecore.HardwareObjects.ISPyBClient import ISPyBClient, trace, utf_encode +from mxcubecore import HardwareRepository as HWR +from suds import WebFault +try: + from urlparse import urljoin + from urllib2 import URLError +except Exception: + # Python3 + from urllib.parse import urljoin + from urllib.error import URLError + +from suds.sudsobject import asdict + +__credits__ = ["ALBA Synchrotron"] +__version__ = "3" +__category__ = "General" + + +class XalocISPyBClient(ISPyBClient): + + def __init__(self, *args): + ISPyBClient.__init__(self, *args) + self.logger = logging.getLogger("HWR.XalocISPyBClient") + + def init(self): + ISPyBClient.init(self) + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + + def ldap_login(self, login_name, psd, ldap_connection): + # overwrites standard ldap login is ISPyBClient2.py + # to query for homeDirectory + + if ldap_connection is None: + ldap_connection = self.ldapConnection + + ok, msg = ldap_connection.login( + login_name, psd, fields=[ + "uid", "homeDirectory"]) + self.logger.debug("ALBA LDAP login success %s (msg: %s)" % (ok, msg)) + if ok: + vals = ldap_connection.get_field_values() + if vals != None: + if 'homeDirectory' in vals: + home_dir = vals['homeDirectory'][0] + self.logger.debug("The homeDirectory for user %s is %s" % + (login_name, home_dir)) + HWR.beamline.session.set_ldap_homedir(home_dir) + else: + self.logger.error( "ALBA LDAP error, no home directory found for proposal %s" % (login_name) ) + home_dir = '/tmp' + HWR.beamline.session.set_ldap_homedir(home_dir) + + return ok, msg + + def translate(self, code, what): + """ + Given a proposal code, returns the correct code to use in the GUI, + or what to send to LDAP, user office database, or the ISPyB database. + """ + self.logger.debug("Translating %s %s" % (code, what)) + if what == 'ldap': + if code == 'mx': + return 'u' + + if what == 'ispyb': + if code == 'u' or code == 'uind-': + return 'mx' + + return code + + def prepare_collect_for_lims(self, mx_collect_dict): + # Attention! directory passed by reference. modified in place + + for i in range(4): + try: + prop = 'xtalSnapshotFullPath%d' % (i + 1) + path = mx_collect_dict[prop] + ispyb_path = HWR.beamline.session.path_to_ispyb(path) + logging.debug("%s = %s " % (prop, ispyb_path)) + mx_collect_dict[prop] = ispyb_path + except BaseException as e: + logging.debug("Error when preparing collection for LIMS\n%s" % str(e)) + + def prepare_image_for_lims(self, image_dict): + for prop in ['jpegThumbnailFileFullPath', 'jpegFileFullPath']: + try: + path = image_dict[prop] + ispyb_path = HWR.beamline.session.path_to_ispyb(path) + image_dict[prop] = ispyb_path + except BaseException as e: + logging.debug("Error when preparing image for LIMS\n%s" % str(e)) + + @trace + def get_samples(self, proposal_id, session_id): + response_samples = None + + if self._tools_ws: + try: + response_samples = self._tools_ws.service.findSampleInfoLightForProposal( + proposal_id, self.beamline_name + ) + + response_samples = [ + utf_encode(asdict(sample)) for sample in response_samples + ] + #logging.getLogger("HWR").debug("%s" % response_samples) + # response_samples holds an array of dictionaries. Each dictionary represents a sample. + # the basket location in the robot is held in the key containerSampleChangerLocation + # the sample location in the basket is held in the key sampleLocation + # eg sample_list[0]['containerSampleChangerLocation'] returns '1' + # and sample_list[0]['sampleLocation'] returns '1' + + except WebFault as e: + logging.getLogger("ispyb_client").exception(str(e)) + except URLError: + logging.getLogger("ispyb_client").exception(_CONNECTION_ERROR_MSG) + else: + logging.getLogger("ispyb_client").exception( + "Error in get_samples: could not connect to server" + ) + + self.emit("ispyb_sync_successful") + + return response_samples + + def next_sample_by_SC_position(self, input_sample_location ): + input_sample_container = input_sample_location[0] + input_sample_num = input_sample_location[1] + self.logger.debug( + "next_sample_by_SC_position: searching for next sample, current location %s" % str(input_sample_location) + ) + input_sample_type = HWR.beamline.sample_changer.basket_types[ input_sample_container ]# spine or unipuck + + sample_dict = self.get_samples( + HWR.beamline.session.proposal_id, HWR.beamline.session.session_id + ) + + next_sample_container = HWR.beamline.sample_changer.number_of_baskets+1 #+1 # more than max number of containers + #next_sample_container = 17 + next_sample_num = 100000 + suitable_sample_in_input_container = False + for sample in sample_dict: + if sample['containerSampleChangerLocation'] != 'None' and \ + HWR.beamline.sample_changer.get_cassette_type( int(sample['containerSampleChangerLocation']) ) == \ + HWR.beamline.sample_changer.get_cassette_type( input_sample_container ): + #if sample['containerSampleChangerLocation'] != 'None': + self.logger.debug("next sample container %s" % sample['containerSampleChangerLocation'] ) + #print("next sample container %s" % sample['containerSampleChangerLocation'] ) + first_sample_num = 0 + if int(sample['containerSampleChangerLocation']) == input_sample_container: + first_sample_num = input_sample_num + self.logger.debug(" sample in same container %s" % sample['containerSampleChangerLocation'] ) + #print(" sample in same container %s" % sample['containerSampleChangerLocation'] ) + if int( sample['sampleLocation'] ) > first_sample_num: + self.logger.debug(" suitable sample %s in same container %s" % (sample['sampleLocation'], sample['containerSampleChangerLocation'] ) ) + #print(" suitable sample %s in same container %s" % (sample['sampleLocation'], sample['containerSampleChangerLocation'] ) ) + suitable_sample_in_input_container = True + next_sample_container = input_sample_container + if int( sample['sampleLocation'] ) < next_sample_num: + next_sample_num = int( sample['sampleLocation'] ) + if next_sample_num == input_sample_num+1: break + elif int(sample['containerSampleChangerLocation']) > input_sample_container and \ + not suitable_sample_in_input_container: + if int(sample['containerSampleChangerLocation']) < next_sample_container: + self.logger.debug("found container %s, which is closer to input container %s" % ( sample['containerSampleChangerLocation'], input_sample_container ) ) + #print("found container %s, which is closer to input container %s" % ( sample['containerSampleChangerLocation'], input_sample_container ) ) + next_sample_container = int(sample['containerSampleChangerLocation']) + next_sample_num = 100000 + first_sample_num = 0 + if int( sample['sampleLocation'] ) > first_sample_num and int( sample['sampleLocation'] ) < next_sample_num: + self.logger.debug("next sample found container %s, location %s" % + ( sample['containerSampleChangerLocation'], sample['sampleLocation'] ) + ) + #print("next sample found: container %s, location %s" % ( sample['containerSampleChangerLocation'], sample['sampleLocation'] ) ) + next_sample_num = int( sample['sampleLocation'] ) + +# For testing purposes, delete... +#sample_dict = [] +#for container in range(9): + #for sample in range(16): + #if container != 2: sample_dict.append( {'containerSampleChangerLocation': 9-container, 'sampleLocation': sample}) + + if next_sample_container == HWR.beamline.sample_changer.number_of_baskets+1: return -1,-1 + return next_sample_container, next_sample_num + +def test_hwo(hwo): + proposal = 'mx2018002222' + pasw = '2222008102' + + info = hwo.login(proposal, pasw) + # info = hwo.get_proposal(proposal_code, proposal_number) + # info = hwo.get_proposal_by_username("u2020000007") + print(info['status']) + + print("Getting associated samples") + session_id = 58248 + proposal_id = 8250 + samples = hwo.get_samples(proposal_id, session_id) + print(samples) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocImageTracking.py b/mxcubecore/HardwareObjects/ALBA/XalocImageTracking.py new file mode 100755 index 0000000000..50414ef143 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocImageTracking.py @@ -0,0 +1,116 @@ +""" +[Name] XalocImageTracking + +[Description] Hardware object used to control image tracking +By default ADXV is used + +Copy from EMBLImageTracking +""" +import os +import time +import logging +import socket +from mxcubecore.BaseHardwareObjects import Device + + +class XalocImageTracking(Device): + + def __init__(self, *args): + Device.__init__(self, *args) + self.logger = logging.getLogger("HWR.XalocImageTracking") + + # self.cmd_start = None + # self.cmd_stop = None + self.cmd_send_image = None + + # self.chan_state = None + # self.chan_status = None + # self.image_tracking_enabled = None + + def init(self): + + # self.chan_state = self.getChannelObject("State") + # self.chan_status = self.getChannelObject("Status") + # self.connect(self.chan_state, "update", self.state_changed) + # + # self.cmd_start = self.getCommandObject('start') + # self.cmd_stop = self.getCommandObject('stop') + self.cmd_send_image = self.get_command_object('send_image') + + # def enable_image_tracking_changed(self, state): + # self.logger.debug('enable_image_tracking_changed: %s' % state) + # self.image_tracking_enabled = state + # self.emit("imageTrackingEnabledChanged", (self.image_tracking_enabled, )) + # + # def state_changed(self, state): + # self.logger.debug('state_changed: %s' % state) + # if self.state != state: + # self.state = state + # self.emit("stateChanged", (self.state, )) + # + # def is_tracking_enabled(self): + # self.logger.debug('is_tracking enabled') + # if self.chan_enable_image_tracking is not None: + # return self.chan_enable_image_tracking.get_value() + # + # def set_image_tracking_state(self, state): + # self.logger.debug('set image tracking state: %s' % state) + # if self.chan_enable_image_tracking is not None: + # self.chan_enable_image_tracking.set_value(state) + + def load_image(self, image_name): + self.logger.debug('load_image: %s' % image_name) + self.cmd_send_image(image_name) + + +# This was a first version, not based on the Tango DS for the ADXV +class XalocImageTrackingLocal(Device): + + def __init__(self, *args): + Device.__init__(self, *args) + self.logger = logging.getLogger("HWR.XalocImageTrackingLocal") + self.binary = None + self.host = None + self.port = None + self.autofront = None + self.start_adxv_cmd = None + + def init(self): + self.binary = self.get_property('executable') + self.host = self.get_property('host') + self.port = self.get_property('port', '8100') + self.autofront = self.get_property('autofront', True) + + if self.binary: + _cmd = '{} -socket {}'.format(self.binary, self.port) + if self.host: + self.start_adxv_cmd = 'ssh {} "{}"'.format(self.host, _cmd) + else: + self.host = socket.gethostname() + self.start_adxv_cmd = _cmd + + def load_image(self, image_name): + self._load_image(str(image_name)) + + def _load_image(self, image_file_name): + """ + Send the image path associated to this spot to the adxv via socket. + + :param image_file_name: image file associated to the spot. + :return: None + """ + def send(): + self.logger.debug( + "Opening socket connection for image: %s" % image_file_name) + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect((self.host, self.port)) + self.logger.debug("Sending image {}".format(image_file_name)) + if self.autofront: + s.send("raise_window Image\n") + s.send("load_image %s\n" % image_file_name) + try: + send() + except Exception as e: + os.system(self.start_adxv_cmd) + time.sleep(2) + send() diff --git a/mxcubecore/HardwareObjects/ALBA/XalocLN2Shower.py b/mxcubecore/HardwareObjects/ALBA/XalocLN2Shower.py new file mode 100755 index 0000000000..d1d2cb02d9 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocLN2Shower.py @@ -0,0 +1,210 @@ +# +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] +Liquid nitrogen shower hardware object + +[Description] +Specific HwObj for the liquid nitrogen pump installed at XALOC to wash the crystal + +[Emitted signals] +- ln2showerIsPumpingChanged +- ln2showerFault + +TODO: when the dewar is empty, the operation is INVALID and the State is FAULT +""" + +import logging +import PyTango +import time + +from taurus.core.tango.enums import DevState + +from mxcubecore import HardwareRepository as HWR +from mxcubecore.BaseHardwareObjects import HardwareObject + +__credits__ = ["ALBA Synchrotron"] +__version__ = "3" +__category__ = "General" +__author__ = "Roeland Boer" + +class XalocLN2Shower(HardwareObject): + """ + Specific liquid nitrogen shower HwObj for XALOC beamline. + """ + + def __init__(self, name): + HardwareObject.__init__(self, name) + + self.logger = logging.getLogger("HWR.XalocLN2Shower") + self.userlogger = logging.getLogger("user_level_log") + + self.username = None + self.chn_operation_mode = None + self.chn_state = None + self.operation_mode = None + self.state = None + self.is_pumping_attr = None + self.cmd_ln2shower_wash = None + self.cmd_ln2shower_cold = None + self.cmd_ln2shower_setflow = None + self.cmd_ln2shower_on = None + self.cmd_ln2shower_off = None + self.cmd_ln2shower_sleep = None + + self.wash_mounted_crystals = None # wash every crystal mounted by robot + self.robot_path_is_safe = None + self.sample_changer_loading = None + + self.collecting = None + self.super_hwobj = None + + + def init(self): + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + self.username = self.get_property("username") + self.wash_mounted_crystals = self.get_property("wash_mounted_crystals") + + self.chn_operation_mode = self.get_channel_object("operation_mode") + self.chn_state = self.get_channel_object("State") + + self.cmd_ln2shower_wash = self.get_command_object("ln2shower_wash") + self.cmd_ln2shower_cold = self.get_command_object("ln2shower_cold") + self.cmd_ln2shower_setflow = self.get_command_object("ln2shower_setflow") + self.cmd_ln2shower_on = self.get_command_object("ln2shower_on") + self.cmd_ln2shower_off = self.get_command_object("ln2shower_off") + self.cmd_ln2shower_sleep = self.get_command_object("ln2shower_sleep") + + if HWR.beamline.sample_changer is not None: + self.robot_path_is_safe = HWR.beamline.sample_changer.path_safe() + self.sample_changer_loading = HWR.beamline.sample_changer.cats_running + + if HWR.beamline.detector is not None: + if HWR.beamline.detector.get_cam_state() == "RUNNING": + self.collecting = True + elif HWR.beamline.detector.get_cam_state() == "STANDBY": + self.collecting = False + else: + raise Exception("The detector seems to be in a funny state") + + self.super_hwobj = self.get_object_by_role('beamline-supervisor') + + self.connect(self.chn_operation_mode, "update", self.operation_mode_changed) + self.connect(self.chn_state, "update", self.state_changed) + + if HWR.beamline.collect is not None: + self.connect( + HWR.beamline.collect, "collectStarted", self.collect_started + ) + self.connect( + HWR.beamline.collect, "collectOscillationFinished", self.collect_finished + ) + self.connect( + HWR.beamline.collect, "collectOscillationFailed", self.collect_finished + ) + + if HWR.beamline.sample_changer is not None: + HWR.beamline.sample_changer.connect("path_safeChanged", self.path_safe_changed) + HWR.beamline.sample_changer.connect("loadedSampleChanged", self.loaded_sample_changed) + + def collect_started(self, owner, num_oscillations): + #logging.getLogger("user_level_log").info("Collection started in sample_control_brick") + self.collecting = True + + def collect_finished(self, owner, state, message, *args): + #logging.getLogger("user_level_log").info("Collection finished in sample_control_brick") + self.collecting = False + + def path_safe_changed(self, value): + self.robot_path_is_safe = value + HWR.beamline.diffractometer.wait_device_ready() + if value == False: + self.sample_changer_loading = True + if self.wash_mounted_crystals and HWR.beamline.diffractometer.get_current_phase() == 'Transfer': + self.run_ln2shower_wash() + else: self.sample_changer_loading = False + + def run_ln2shower_wash(self, washflow = 120): + #TODO: move diff to transfer phase first, use XalocMiniDiff set_phase method + + self.logger.debug( "get_current_phase %s" % HWR.beamline.diffractometer.get_current_phase() ) + self.super_hwobj.wait_ready(timeout = 30) + if not self.collecting: + if HWR.beamline.diffractometer.get_current_phase() != HWR.beamline.diffractometer.PHASE_TRANSFER: + HWR.beamline.diffractometer.set_diff_phase( HWR.beamline.diffractometer.PHASE_TRANSFER, timeout = 20 ) + if HWR.beamline.diffractometer.get_current_phase() == HWR.beamline.diffractometer.PHASE_TRANSFER: + self.cmd_ln2shower_wash(washflow, wait = False) + return True + else: + return False + else: + self.logger.debug( "Cannot use the shower while collecting!! Wait till the collection is finished" ) + return False + + return True + + def run_ln2shower_off(self): + self.cmd_ln2shower_off(wait = False) + + def operation_mode_changed(self, value): + """ + value can be None! + """ + if value is not None: value = int(value) + if self.operation_mode != value: + self.operation_mode = value + if self.operation_mode in [3]: + self.is_pumping_attr = True + else: + self.is_pumping_attr = False + self.emit("ln2showerIsPumpingChanged", self.is_pumping_attr) + + def state_changed(self, value): + """ + value can be DevState.FAULT, DevState.ON + """ + if value is not None: + if self.state != value: + self.state = value + self.emit("stateChanged", self.state) + if value in [DevState.FAULT]: + self.emit("ln2showerFault", True) + else: + self.emit("ln2showerFault", False) + + def is_pumping(self): + return self.is_pumping_attr + + def loaded_sample_changed(self, sample): + """ + For each getput, the signal is emitted twice: once when the crystal is removed, + once when the new crystal is mounted. + For a get or a put, only one signal is sent + Want only the first signal and turn off the shower. + + TODO: when a put is done, the waiting time should be reduced, because the robot is in and out much faster + """ + time_margin = 2 # waiting time between detecting change of sample and turning off the shower + if self.sample_changer_loading: + if self.wash_mounted_crystals: + time.sleep( time_margin ) # give the CATS time to load the next (in case of getput) + self.run_ln2shower_off() + self.sample_changer_loading = False + diff --git a/mxcubecore/HardwareObjects/ALBA/XalocMachineInfo.py b/mxcubecore/HardwareObjects/ALBA/XalocMachineInfo.py index 0a2340d5cb..13fefd5703 100644 --- a/mxcubecore/HardwareObjects/ALBA/XalocMachineInfo.py +++ b/mxcubecore/HardwareObjects/ALBA/XalocMachineInfo.py @@ -1,185 +1,126 @@ # # Project: MXCuBE -# https://github.com/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 +# it under the terms of the GNU 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. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the` +# GNU 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 . +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . """ [Name] -ALBAMachineInfo +XalocMachineInfo [Description] Hardware Object is used to get relevant machine information (machine current, time to next injection, status, etc) -Based on EMBL HwObj -[Channels] -- MachineCurrent -- TopUpRemaining -- State - -[Commands] - -[Emited signals] +[Emitted signals] - valuesChanged - -[Functions] -- None - -[Included Hardware Objects] -- None - - -Example Hardware Object XML file : -================================== - - Mach - mach/ct/gateway - State - Current - TopUpRemaining - """ +from __future__ import print_function + import logging -import time -from gevent import spawn -from urllib2 import urlopen -from datetime import datetime, timedelta -from mxcubecore import HardwareRepository as HWR from mxcubecore.BaseHardwareObjects import Equipment - -__author__ = "Jordi Andreu" -__credits__ = ["MXCuBE collaboration"] - -__version__ = "2.2." -__maintainer__ = "Jordi Andreu" -__email__ = "jandreu[at]cells.es" -__status__ = "Draft" +__credits__ = ["ALBA Synchrotron"] +__version__ = "2.3" +__category__ = "General" class XalocMachineInfo(Equipment): - """ - Descript. : Displays actual information about the machine status. - """ def __init__(self, name): Equipment.__init__(self, name) - """ - Descript. : - """ - # Parameters values - self.values_dict = {} - self.values_dict["mach_current"] = None - self.values_dict["mach_status"] = "" - self.values_dict["topup_remaining"] = "" - # Dictionary for booleans indicating if values are in range - # self.values_in_range_dict = {} + self.logger = logging.getLogger('HWR.MachineInfo') + self.values_dict = dict() + self.values_dict['mach_current'] = None + self.values_dict['mach_status'] = "" + self.values_dict['topup_remaining'] = "" + self.chan_mach_current = None self.chan_mach_status = None self.chan_topup_remaining = None def init(self): - """ - Descript. : Inits channels from xml configuration. - """ + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) try: - self.chan_mach_current = self.get_channel_object("MachCurrent") + self.chan_mach_current = self.get_channel_object('MachCurrent') if self.chan_mach_current is not None: self.chan_mach_current.connect_signal( - "update", self.mach_current_changed - ) + 'update', self.mach_current_changed) - self.chan_mach_status = self.get_channel_object("MachStatus") + self.chan_mach_status = self.get_channel_object('MachStatus') if self.chan_mach_status is not None: - self.chan_mach_status.connect_signal("update", self.mach_status_changed) + self.chan_mach_status.connect_signal('update', self.mach_status_changed) - self.chan_topup_remaining = self.get_channel_object("TopUpRemaining") + self.chan_topup_remaining = self.get_channel_object('TopUpRemaining') if self.chan_topup_remaining is not None: self.chan_topup_remaining.connect_signal( - "update", self.topup_remaining_changed - ) + 'update', self.topup_remaining_changed) except KeyError: - logging.getLogger().warning("%s: cannot read machine info", self.name()) + self.logger.warning('%s: cannot read machine info', self.name()) def mach_current_changed(self, value): - """ - Descript. : Function called if the machine current is changed - Arguments : new machine current (float) - Return : - - """ - if ( - self.values_dict["mach_current"] is None - or abs(self.values_dict["mach_current"] - value) > 0.10 - ): - self.values_dict["mach_current"] = value - self.re_emit_values() + if self.values_dict['mach_current'] is None or\ + abs(self.values_dict['mach_current'] - value) > 0.10: + self.values_dict['mach_current'] = value + self.update_values() + # self.logger.debug('New machine current value=%smA' % value) def mach_status_changed(self, status): - """ - Descript. : Function called if machine status is changed - Arguments : new machine status (string) - Return : - - """ - self.values_dict["mach_status"] = str(status) - self.re_emit_values() + self.values_dict['mach_status'] = str(status).split('.')[-1] + self.update_values() + # self.logger.debug('New machine status=%s' % status) def topup_remaining_changed(self, value): - """ - Descript. : Function called if topup ramaining is changed - Arguments : new topup remainin (float) - Return : - - """ - self.values_dict["topup_remaining"] = value - self.re_emit_values() - - def re_emit_values(self): - """ - Descript. : Updates storage disc information, detects if intensity - and storage space is in limits, forms a value list - and value in range list, both emited by qt as lists - Arguments : - - Return : - - """ - - values_to_send = [] - values_to_send.append(self.values_dict["mach_current"]) - values_to_send.append(self.values_dict["mach_status"]) - values_to_send.append(self.values_dict["topup_remaining"]) - - self.emit("valuesChanged", values_to_send) + self.values_dict['topup_remaining'] = value + self.update_values() + # self.logger.debug('New top-up remaining time=%ss' % value) + + def update_values(self): + values_to_send = list() + values_to_send.append(self.values_dict['mach_current']) + values_to_send.append(self.values_dict['mach_status']) + values_to_send.append(self.values_dict['topup_remaining']) + + self.emit('valuesChanged', values_to_send) + # self.logger.debug("SIGNAL valuesChanged emitted") def get_mach_current(self): - return self.chan_mach_current.get_value() - # return self.values_dict['mach_current'] + value = None + try: + value = self.chan_mach_current.get_value() + except Exception as e: + self.logger.error('Cannot read machine current value.\n%s' % str(e)) + finally: + return value + + def get_current(self): + return self.get_mach_current() - # def get_current_value(self): - # """ - # Descript. : - # """ - # return self.values_dict['current'] + def get_message(self): + return 'Machine info status: %s' % str(self.get_mach_status()).split('.')[-1] def get_mach_status(self): return self.chan_mach_status.get_value() - # return self.values_dict['mach_status'] - def get_topup_remaining(self): return self.chan_topup_remaining.get_value() -# return self.values_dict['remaining'] +def test_hwo(hwo): + print(hwo.get_message()) + print("Current = %s" % hwo.get_current()) + print("Top-Up remaining = %s" % hwo.get_topup_remaining()) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocMiniDiff.py b/mxcubecore/HardwareObjects/ALBA/XalocMiniDiff.py old mode 100644 new mode 100755 index 650a11e8cf..5c59113927 --- a/mxcubecore/HardwareObjects/ALBA/XalocMiniDiff.py +++ b/mxcubecore/HardwareObjects/ALBA/XalocMiniDiff.py @@ -1,267 +1,1316 @@ +# +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] +XalocMiniDiff + +[Description] +Specific HwObj for M2D2 diffractometer @ ALBA + +[Emitted signals] +- pixelsPerMmChanged +- kappaMotorMoved +- phiMotorMoved +- stateChanged +- zoomMotorPredefinedPositionChanged +- minidiffStateChanged +- minidiffPhaseChanged +""" + +from __future__ import print_function + import logging import time -from mxcubecore.HardwareObjects.GenericDiffractometer import ( - GenericDiffractometer, -) -from gevent.event import AsyncResult import gevent +import math +import os +import tempfile +from PIL import Image +import numpy as np +from mxcubecore import HardwareRepository as HWR + +logger = logging.getLogger('HWR') + +try: + logger.warning("Importing lucid3") + import lucid3 as lucid +except ImportError: + try: + logger.warning("Could not find lucid3, importing lucid") + import lucid + except ImportError: + logger.warning("Could not find autocentring library, automatic centring is disabled") + +import queue_model_objects +import queue_entry + +from mxcubecore.HardwareObjects.GenericDiffractometer import GenericDiffractometer, DiffractometerState +from taurus.core.tango.enums import DevState + +__credits__ = ["ALBA Synchrotron"] +__version__ = "3" +__category__ = "General" +__author__ = "Roeland Boer, Jordi Andreu, Vicente Rey" class XalocMiniDiff(GenericDiffractometer): + """ + Specific diffractometer HwObj for XALOC beamline. + """ + + PHASE_TRANSFER = "Transfer" + PHASE_CENTRING = "Sample" + PHASE_COLLECTION = "Collect" + PHASE_BEAM = "Beam" + PHASE_UNKNOWN = "Unknown" + def __init__(self, *args): GenericDiffractometer.__init__(self, *args) + self.logger = logging.getLogger("HWR.XalocMiniDiff") + self.userlogger = logging.getLogger("user_level_log") + + self.chan_phase = None + self.chan_state = None + self.phi_motor_hwobj = None + self.phiz_motor_hwobj = None + self.phiy_motor_hwobj = None + self.zoom_motor_hwobj = None + self.focus_motor_hwobj = None + self.sample_x_motor_hwobj = None + self.sample_y_motor_hwobj = None + self.kappa_motor_hwobj = None + self.kappa_phi_motor_hwobj = None + + self.omegaz_reference = None + self.omegaz_reference_channel = None + + self.phi_direction = None # direction of the phi rotation angle as defined in centringMath + self.phi_centring_direction = None # change centring direction depending on phi value + self.saved_zoom_pos = None + self.sample_has_been_centred = None + + # Number of images and total angle range used in automatic centering, defined in centring-math.xml + self.numCentringImages = None + self.centringAngleRange = None self.centring_hwobj = None + self.cmd_go_transfer = None + self.cmd_go_sample_view = None + + # For testing + self.no_sample = None + def init(self): - self.calibration = self.get_object_by_role("calibration") - self.centring_hwobj = self.get_object_by_role("centring") + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + + self.no_sample = self.get_property('no_sample', False) + + self.centring_hwobj = self.get_object_by_role('centring') + + #if HWR.beamline.centring is None: if self.centring_hwobj is None: - logging.getLogger("HWR").debug("EMBLMinidiff: Centring math is not defined") + self.logger.debug('XalocMinidiff: Centring math is not defined') - self.cmd_start_auto_focus = self.get_command_object("startAutoFocus") + self.chan_phase = self.get_channel_object("Phase") + self.connect(self.chan_phase, "update", self.phase_changed) + self.chan_state = self.get_channel_object("State") + self.connect(self.chan_state, "update", self.state_changed) - self.phi_motor_hwobj = self.get_object_by_role("phi") - self.phiz_motor_hwobj = self.get_object_by_role("phiz") - self.phiy_motor_hwobj = self.get_object_by_role("phiy") - self.zoom_motor_hwobj = self.get_object_by_role("zoom") - self.focus_motor_hwobj = self.get_object_by_role("focus") - self.sample_x_motor_hwobj = self.get_object_by_role("sampx") - self.sample_y_motor_hwobj = self.get_object_by_role("sampy") + self.cmd_go_transfer = self.get_command_object("go_transfer") + self.cmd_go_sample_view = self.get_command_object("go_sample_view") + + self.phi_motor_hwobj = self.get_object_by_role('phi') + self.phiz_motor_hwobj = self.get_object_by_role('phiz') + self.phiy_motor_hwobj = self.get_object_by_role('phiy') + self.zoom_motor_hwobj = self.get_object_by_role('zoom') + self.focus_motor_hwobj = self.get_object_by_role('focus') + self.sample_x_motor_hwobj = self.get_object_by_role('sampx') + self.sample_y_motor_hwobj = self.get_object_by_role('sampy') + self.kappa_motor_hwobj = self.get_object_by_role('kappa') + self.kappa_phi_motor_hwobj = self.get_object_by_role('kappa_phi') + + self.omegaz_reference_channel = self.get_channel_object("omegazReference") + + #for axis in HWR.beamline.centring.gonioAxes: + for axis in self.centring_hwobj.gonioAxes: + if axis['motor_name'] == 'phi': + self.logger.warning('XalocMinidiff: phi rotation direction is %s' % str(axis['direction']) ) + self.phi_direction = sum( axis['direction'] ) + self.phi_centring_direction = 1 + self.saved_zoom_pos = self.zoom_motor_hwobj.get_value() + self.logger.warning('XalocMinidiff: digital zoom position %s' % str(self.saved_zoom_pos) ) + + # For automatic centring + #self.numCentringImages = HWR.beamline.centring.get_property('numCentringImages') + self.numCentringImages = self.centring_hwobj.get_property('numCentringImages') + if self.numCentringImages < 2: + self.logger.warning('XalocMinidiff: numCentringImages should be at least 2, reset to 2') + self.numCentringImages = 2 + #self.centringAngleRange = HWR.beamline.centring.get_property('centringAngleRange') + self.centringAngleRange = self.centring_hwobj.get_property('centringAngleRange') + if self.centringAngleRange > 360: + self.logger.warning('XalocMinidiff: centringAngleRange should be smaller than 360 degrees, reset to 360 degrees') + self.centringAngleRange = 360 + #self.numAutoCentringCycles = HWR.beamline.centring.get_property('numAutoCentringCycles') + self.numAutoCentringCycles = self.centring_hwobj.get_property('numAutoCentringCycles') + if self.centringAngleRange < 0: + self.logger.warning('XalocMinidiff: numAutoCentringCycles should be at least 1, reset to 1') + self.numAutoCentringCycles = 1 if self.phi_motor_hwobj is not None: self.connect( - self.phi_motor_hwobj, "stateChanged", self.phi_motor_state_changed - ) + self.phi_motor_hwobj, + 'stateChanged', + self.phi_motor_state_changed) self.connect(self.phi_motor_hwobj, "valueChanged", self.phi_motor_moved) + self.current_motor_positions["phi"] = self.phi_motor_hwobj.get_value() + if self.phi_motor_hwobj.get_value() > 0: self.phi_centring_direction = -1 + else: self.phi_centring_direction = 1 else: - logging.getLogger("HWR").error("EMBLMiniDiff: Phi motor is not defined") + self.logger.error('Phi motor is not defined') if self.phiz_motor_hwobj is not None: self.connect( - self.phiz_motor_hwobj, "stateChanged", self.phiz_motor_state_changed - ) - self.connect(self.phiz_motor_hwobj, "valueChanged", self.phiz_motor_moved) + self.phiz_motor_hwobj, + 'stateChanged', + self.phiz_motor_state_changed) + self.connect( + self.phiz_motor_hwobj, + 'valueChanged', + self.phiz_motor_moved) + self.current_motor_positions["phiz"] = self.phiz_motor_hwobj.get_value() else: - logging.getLogger("HWR").error("EMBLMiniDiff: Phiz motor is not defined") + self.logger.error('Phiz motor is not defined') if self.phiy_motor_hwobj is not None: self.connect( - self.phiy_motor_hwobj, "stateChanged", self.phiy_motor_state_changed - ) - self.connect(self.phiy_motor_hwobj, "valueChanged", self.phiy_motor_moved) + self.phiy_motor_hwobj, + 'stateChanged', + self.phiy_motor_state_changed) + self.connect( + self.phiy_motor_hwobj, + 'valueChanged', + self.phiy_motor_moved) + self.current_motor_positions["phiy"] = self.phiy_motor_hwobj.get_value() else: - logging.getLogger("HWR").error("EMBLMiniDiff: Phiy motor is not defined") + self.logger.error('Phiy motor is not defined') if self.zoom_motor_hwobj is not None: self.connect( - self.zoom_motor_hwobj, "valueChanged", self.zoom_position_changed - ) + self.zoom_motor_hwobj, + 'valueChanged', + self.zoom_position_changed) self.connect( self.zoom_motor_hwobj, - "predefinedPositionChanged", - self.zoom_motor_predefined_position_changed, - ) + 'predefinedPositionChanged', + self.zoom_motor_predefined_position_changed) self.connect( - self.zoom_motor_hwobj, "stateChanged", self.zoom_motor_state_changed - ) + self.zoom_motor_hwobj, + 'stateChanged', + self.zoom_motor_state_changed) else: - logging.getLogger("HWR").error("EMBLMiniDiff: Zoom motor is not defined") + self.logger.error('Zoom motor is not defined') if self.sample_x_motor_hwobj is not None: self.connect( self.sample_x_motor_hwobj, - "stateChanged", - self.sampleX_motor_state_changed, - ) + 'stateChanged', + self.sampleX_motor_state_changed) self.connect( - self.sample_x_motor_hwobj, "valueChanged", self.sampleX_motor_moved - ) + self.sample_x_motor_hwobj, + 'valueChanged', + self.sampleX_motor_moved) + self.current_motor_positions["sampx"] = self.sample_x_motor_hwobj.get_value() else: - logging.getLogger("HWR").error("EMBLMiniDiff: Sampx motor is not defined") + self.logger.error('Sampx motor is not defined') if self.sample_y_motor_hwobj is not None: self.connect( self.sample_y_motor_hwobj, - "stateChanged", - self.sampleY_motor_state_changed, - ) + 'stateChanged', + self.sampleY_motor_state_changed) self.connect( - self.sample_y_motor_hwobj, "valueChanged", self.sampleY_motor_moved - ) + self.sample_y_motor_hwobj, + 'valueChanged', + self.sampleY_motor_moved) + self.current_motor_positions["sampy"] = self.sample_y_motor_hwobj.get_value() else: - logging.getLogger("HWR").error("EMBLMiniDiff: Sampx motor is not defined") + self.logger.error('Sampx motor is not defined') if self.focus_motor_hwobj is not None: - self.connect(self.focus_motor_hwobj, "valueChanged", self.focus_motor_moved) + self.connect( + self.focus_motor_hwobj, + 'valueChanged', + self.focus_motor_moved) + + if self.kappa_motor_hwobj is not None: + self.connect( + self.kappa_motor_hwobj, + 'stateChanged', + self.kappa_motor_state_changed) + self.connect( + self.kappa_motor_hwobj, + "valueChanged", + self.kappa_motor_moved) + self.current_motor_positions["kappa"] = self.kappa_motor_hwobj.get_value() + else: + self.logger.error('Kappa motor is not defined') + + if self.kappa_phi_motor_hwobj is not None: + self.connect( + self.kappa_phi_motor_hwobj, + 'stateChanged', + self.kappa_phi_motor_state_changed) + self.connect( + self.kappa_phi_motor_hwobj, + "valueChanged", + self.kappa_phi_motor_moved) + self.current_motor_positions["kappa_phi"] = self.kappa_phi_motor_hwobj.get_value() + else: + self.logger.error('Kappa-Phi motor is not defined') GenericDiffractometer.init(self) - def getCalibrationData(self, offset=None): - calibx, caliby = self.calibration.getCalibration() - return 1000.0 / caliby, 1000.0 / caliby - # return 1000./self.md2.CoaxCamScaleX, 1000./self.md2.CoaxCamScaleY + # overwrite default centring motors configuration from GenericDiffractometer + # when using sample_centring. Fix phiz position to a reference value. + self.omegaz_reference = self.omegaz_reference_channel.get_value() - def get_pixels_per_mm(self): - px_x, px_y = self.getCalibrationData() - return (px_x, px_y) + queue_model_objects.CentredPosition.\ + set_diffractometer_motor_names( + "phi", "phiy", "phiz", "sampx", "sampy", "kappa", "kappa_phi") - def update_pixels_per_mm(self, *args): + # TODO: Explicit update would not be necessary, but it is. + # Added to make sure pixels_per_mm is initialised + self.update_pixels_per_mm() + + #Set the beam_x and beam_y positions so the center point is kept + self.current_motor_positions["beam_x"] = (self.beam_position[0] - \ + self.zoom_centre['x'] )/self.pixels_per_mm_x + self.current_motor_positions["beam_y"] = (self.beam_position[1] - \ + self.zoom_centre['y'] )/self.pixels_per_mm_y + + def state_changed(self, state): """ - Descript. : + Overwrites method to map Tango ON state to Diffractometer State Ready. + + @state: Taurus state but string for Ready state + """ + if state == DevState.ON: + state = DiffractometerState.tostring(DiffractometerState.Ready) + + if state != self.current_state: + #self.logger.debug("State changed %s (was: %s)" % + #(str(state), self.current_state)) + self.current_state = state + self.emit("minidiffStateChanged", (self.current_state)) + + def get_state(self): + try: + _value = self.chan_state.get_value() + #self.logger.debug('get_state: (value={0}, type={1})'.format(_value, type(_value))) + except Exception as e: + raise RuntimeError('Cannot get diffractometer state:\n%s' % str(e)) + return _value + #return self.chan_state.get_value() + + + def update_pixels_per_mm(self): + """ + Returns the pixel/mm for x and y. Overrides GenericDiffractometer method. + """ + if self.zoom_motor_hwobj != None: + self.pixels_per_mm_x, self.pixels_per_mm_y = self.zoom_motor_hwobj.get_calibration_pixels_per_mm() + self.emit('pixelsPerMmChanged', ((self.pixels_per_mm_x, self.pixels_per_mm_y), )) + + def get_pixels_per_mm(self, *args): + """ + Emit signal with current pixel/mm values. """ - self.pixels_per_mm_x, self.pixels_per_mm_y = self.getCalibrationData() - self.emit("pixelsPerMmChanged", ((self.pixels_per_mm_x, self.pixels_per_mm_y),)) + return self.pixels_per_mm_x, self.pixels_per_mm_y + + # Overwrite from generic diffractometer + def update_zoom_calibration(self): + """ + This is used by GenericDiffractometer and basically renamed here to specify the calibraion units + """ + self.update_pixels_per_mm() def get_centred_point_from_coord(self, x, y, return_by_names=None): """ + Returns a dictionary with motors name and positions centred corresponding to the camera image point with + coordinates x and y. + It is expected in start_move_to_beam and move_to_beam methods in + GenericDiffractometer HwObj, + Also needed for the calculation of the motor positions after definition of the mesh grid + (Qt4_GraphicsManager, update_grid_motor_positions) + + point x,y is relative to the lower left corner on the camera, this functions returns the motor positions for that point, + where the motors that are changed are phiy and phiz. + + @return: dict """ - return {"omega": [200, 200]} - # raise NotImplementedError + #self.logger.info('get_centred_point_from_coord x %s and y %s and return_by_names %s' % ( x, y, return_by_names ) ) + #self.logger.info('get_centred_point_from_coord pixels_per_mm_x %s and pixels_per_mm_y %s' % ( self.pixels_per_mm_x, self.pixels_per_mm_y ) ) + #self.logger.info('get_centred_point_from_coord beam_position[0] %s and beam_position[1] %s' % + #( self.beam_position[0], self.beam_position[1] ) + #) + + self.update_zoom_calibration() + + loc_centred_point = {} + loc_centred_point['phi'] = self.phi_motor_hwobj.get_value() + loc_centred_point['kappa'] = self.kappa_motor_hwobj.get_value() + loc_centred_point['kappa_phi'] = self.kappa_phi_motor_hwobj.get_value() + loc_centred_point['phiy'] = self.phiy_motor_hwobj.get_value() - ( + ( float( x ) - float( self.beam_position[0] ) ) / + float( self.pixels_per_mm_x ) + ) + + # Overwrite phiz, which should remain in the actual position, hopefully the center of rotation + omegaz_diff = 0 + if self.omegaz_reference_channel != None: + self.omegaz_reference = self.omegaz_reference_channel.get_value() + loc_centred_point['phiz'] = self.omegaz_reference + omegaz_diff = self.phiz_motor_hwobj.get_value() - self.omegaz_reference + else: + loc_centred_point['phiz'] = self.phiz_motor_hwobj.get_value() + + # Calculate the positions of sampx and sampy that correspond to the camera x,y coordinates + vertdist = omegaz_diff + ( float( y ) - float ( self.beam_position[1] ) ) / float (self.pixels_per_mm_y ) + sampxpos = self.sample_x_motor_hwobj.get_value() + sampypos = self.sample_y_motor_hwobj.get_value() + dx, dy = self.vertical_dist_to_samp_pos (self.phi_motor_hwobj.get_value() , vertdist) + + loc_centred_point['sampx'] = sampxpos + dy + loc_centred_point['sampy'] = sampypos + dx + + loc_centred_point = self.add_beam_position_to_centering_motors(loc_centred_point) + + # 20220706 RB: These lines cause the grid to move to the center of camera, do not use! + #if return_by_names: + #loc_centred_point = self.convert_from_obj_to_name(loc_centred_point) + + self.logger.info('get_centred_point_from_coord loc_centred_point %s ' % ( loc_centred_point ) ) + + return loc_centred_point + + def vertical_dist_to_samp_pos(self, phipos, vertdist): + """ + returns the relative displacement of sampx and sampy + """ + d_sampx = 0 + d_sampy = 0 + + #self.logger.debug("phipos %.4f , vertdist %.4f" % ( phipos, vertdist ) ) - def getBeamInfo(self, update_beam_callback): - calibx, caliby = self.calibration.getCalibration() + if self.use_sample_centring: + phi_angle = math.radians(self.centring_phi.direction * \ + phipos ) + else: + phi_angle = math.radians( phipos * self.phi_direction ) - size_x = self.get_channel_object("beamInfoX").get_value() / 1000.0 - size_y = self.get_channel_object("beamInfoY").get_value() / 1000.0 + #self.logger.debug("phi_angle %.4f" % ( phi_angle ) ) - data = {"size_x": size_x, "size_y": size_y, "shape": "ellipse"} + d_sampy = math.cos(phi_angle) * vertdist + d_sampx = math.sin(phi_angle) * vertdist + + return d_sampy, d_sampx - update_beam_callback(data) + # RB: Never called? + #def getBeamInfo(self, update_beam_callback): + #""" + #Update beam info (position and shape) ans execute callback. + #@update_beam_callback: callback method passed as argument. + #""" + #size_x = self.getChannelObject("beamInfoX").get_value() / 1000.0 + #size_y = self.getChannelObject("beamInfoY").get_value() / 1000.0 + + #data = { + #"size_x": size_x, + #"size_y": size_y, + #"shape": "ellipse", + #} + + #update_beam_callback(data) + + # TODO:Implement dynamically + def use_sample_changer(self): + """ + Overrides GenericDiffractometer method. + """ + return True + + # TODO:Implement dynamically def in_plate_mode(self): + """ + Overrides GenericDiffractometer method. + """ return False + # overwrite generic diff method to avoid centering when mounting fails + def start_centring_method(self, method, sample_info=None, wait=False): + """ + method is either of the centring methods defined in diff HW object: + CENTRING_METHOD_MANUAL = "Manual 3-click", CENTRING_METHOD_AUTO = "Computer automatic", CENTRING_METHOD_MOVE_TO_BEAM = "Move to beam" + """ + + if self.current_centring_method is not None: + logging.getLogger("HWR").error( + "Diffractometer: using centring method %s" + % self.current_centring_method + ) + return + curr_time = time.strftime("%Y-%m-%d %H:%M:%S") + self.centring_status = { + "valid": False, + "startTime": curr_time, + "angleLimit": None, + } + self.emit_centring_started(method) + self.logger.debug( + "Diffractometer: centring method (%s)" % str(self.current_centring_method) + ) + + try: + centring_method = self.centring_methods[method] + except KeyError as diag: + logging.getLogger("HWR").error( + "Diffractometer: unknown centring method (%s)" % str(diag) + ) + self.emit_centring_failed() + else: + if HWR.beamline.sample_changer.sample_can_be_centered: + try: + self.prepare_centring() + except Exception as e: + self.userlogger.error("The diffractometer could not be prepared for centering, warn the lc/floor coordinator") + raise Exception(e) + try: + centring_method(sample_info, wait_result=wait) + except Exception: + logging.getLogger("HWR").exception( + "Diffractometer: problem while centring" + ) + self.emit_centring_failed() + else: + logging.getLogger("HWR").error( + "Diffractometer: there was a problem in loading the sample, centering cancelled" + ) + self.emit_centring_failed() + + def manual_centring(self): """ Descript. : """ self.centring_hwobj.initCentringProcedure() - - # self.head_type = self.chan_head_type.get_value() - + if not self.sample_has_been_centred: + self.zoom_motor_hwobj.move_to_position( 1 ) + for click in range(3): self.user_clicked_event = gevent.event.AsyncResult() x, y = self.user_clicked_event.get() + #logger.debug("manual_centring : x %s, y %s" % ( str(x), str(y) ) ) self.centring_hwobj.appendCentringDataPoint( - { - "X": (x - self.beam_position[0]) / self.pixels_per_mm_x, - "Y": (y - self.beam_position[1]) / self.pixels_per_mm_y, - } - ) - + {"X": (x - self.beam_position[0])/ self.pixels_per_mm_x, + "Y": (y - self.beam_position[1])/ self.pixels_per_mm_y}) if self.in_plate_mode(): - dynamic_limits = self.phi_motor_hwobj.get_dynamic_limits() - if click == 0: - self.phi_motor_hwobj.set_value(dynamic_limits[0]) - elif click == 1: - self.phi_motor_hwobj.set_value(dynamic_limits[1]) + pass + ##dynamic_limits = self.phi_motor_hwobj.getDynamicLimits() + #dynamic_limits = self.get_osc_limits() + #if click == 0: + #self.motor_hwobj_dict['phi'].set_value(dynamic_limits[0] + 0.5) + #elif click == 1: + #self.motor_hwobj_dict['phi'].set_value(dynamic_limits[1] - 0.5) + #elif click == 2: + #self.motor_hwobj_dict['phi'].set_value((dynamic_limits[0] + \ + #dynamic_limits[1]) / 2.) else: if click < 2: - self.phi_motor_hwobj.set_value_relative(-90) - # self.omega_reference_add_constraint() - return self.centring_hwobj.centeredPosition(return_by_name=False) + new_pos = self.motor_hwobj_dict['phi'].get_value() + ( self.phi_centring_direction * 90 ) + self.motor_hwobj_dict['phi'].set_value( new_pos ) + #self.omega_reference_add_constraint() + centred_pos_dict = self.centring_hwobj.centeredPosition(return_by_name=False) + + # Fix the omegaz (phiz) motor position to the known center + centred_pos_dict[ self.motor_hwobj_dict['phiz'] ] = self.omegaz_reference - def phi_motor_moved(self, pos): + if not self.sample_has_been_centred: + self.zoom_motor_hwobj.move_to_position( self.saved_zoom_pos) + self.sample_has_been_centred = True + + #self.logger.debug( "centred_pos_dict %s" % str( centred_pos_dict ) ) + + return centred_pos_dict + + def move_to_beam(self, x, y, omega=None): + """ + Descript. : function to create a centring point based on all current motors + positions. + """ + logging.getLogger("HWR").debug("move_to_beam x %s y %s" % (x,y) ) + + try: + pos = self.get_centred_point_from_coord(x, y, return_by_names=False) + if omega is not None: + pos["phiMotor"] = omega + self.move_to_motors_positions(pos) + #self.centring_status["motors"] = self.convert_from_obj_to_name( pos ) + logging.getLogger("HWR").debug("centring_status %s" % self.centring_status) + except Exception: + logging.getLogger("HWR").exception( + "Diffractometer: could not center to beam, aborting" + ) + + def add_beam_position_to_centering_motors(self, motor_pos): + """ + """ + logging.getLogger("HWR").debug( + "motor_pos %s" % str(motor_pos) + ) + motor_pos["beam_x"] = ( + self.beam_position[0] - self.zoom_centre["x"] + ) / self.pixels_per_mm_y + motor_pos["beam_y"] = ( + self.beam_position[1] - self.zoom_centre["y"] + ) / self.pixels_per_mm_x + logging.getLogger("HWR").debug( + "motors %s" % str(motor_pos) + ) + return motor_pos + + def convert_from_obj_to_name(self, motor_pos): + """ + """ + motors = {} + for motor_role in self.centring_motors_list: + motor_obj = self.get_object_by_role(motor_role) + try: + motors[motor_role] = motor_pos[motor_role] + except KeyError: + if motor_obj: + motors[motor_role] = motor_obj.get_value() + motors["beam_x"] = ( + self.beam_position[0] - self.zoom_centre["x"] + ) / self.pixels_per_mm_y + motors["beam_y"] = ( + self.beam_position[1] - self.zoom_centre["y"] + ) / self.pixels_per_mm_x + return motors + + # Override GenericDiffractometer to add prepare_centring, which sets omega velocity to 60. + def start_automatic_centring(self, sample_info=None, loop_only=False, wait_result=None): + """ + Start Automatic centring. Overrides GenericDiffractometer method. + Prepares diffractometer for automatic centring. + """ + self.automatic_centring_try_count = 0 + + self.logger.debug('automatic_centring_try_count: %d, numAutoCentringCycles: %d' % \ + (self.automatic_centring_try_count, self.numAutoCentringCycles) ) + + #TODO: whould the wait_result argument to start_automatic_centring be set to True? + self.emit_progress_message("Automatic centring...") + + #self.logger.debug('Start automatic centring: %s' % self.pixels_per_mm_x) + if self.use_sample_centring: + if self.numAutoCentringCycles > 1: + self.logger.debug( 'Multiple centring not supported when use_sample_centring is set to True' ) + self.userlogger.info( 'Started 1 cycle of automatic centring' ) + self.current_centring_procedure = \ + sample_centring.start_auto(self.camera_hwobj, + {"phi": self.centring_phi, + "phiy": self.centring_phiy, + "sampx": self.centring_sampx, + "sampy": self.centring_sampy, + "phiz": self.centring_phiz }, + self.pixels_per_mm_x, + self.pixels_per_mm_y, + self.beam_position[0], + self.beam_position[1], + msg_cb = self.emit_progress_message, + new_point_cb=lambda point: self.emit("newAutomaticCentringPoint", (point,))) + else: + #TODO: can this be added to a queue and execute the queue? SampleCentringQueueEntry does not work for this + # GPHL uses queue_model_objects.SampleCentring in enqueue_sample_centring + self.userlogger.info( 'Started %d cycles of automatic centring' % self.numAutoCentringCycles ) + for i in range(self.numAutoCentringCycles): + self.current_centring_procedure = gevent.spawn( self.automatic_centring, i ) + self.current_centring_procedure.link(self.centring_done) + + self.sample_has_been_centred = True # used for setting the zoom level + self.zoom_motor_hwobj.move_to_position( self.saved_zoom_pos) + + #TODO: make method called finish_centring to reset values? + + def automatic_centring(self, pid): + """Automatic centring procedure. Rotates n times and executes + centring algorithm. Optimal scan position is detected. + """ + + #self.logger.info("Cued new automatic centring number %d" % pid+1) + + # wait till it is the turn of this cycle + stime = time.time() + timeout = 20 * ( pid + 1 ) + while pid != self.automatic_centring_try_count: + gevent.sleep(1) + if time.time() - stime > timeout: + self.cancel_centring_method() + + self.userlogger.info("Started new automatic centring cycle %d of %d" % ( pid+1, self.numAutoCentringCycles ) ) + + if self.phi_motor_hwobj.get_value() > 0: self.phi_centring_direction = -1 + else: self.phi_centring_direction = 1 + + # This cycle now starts + if pid == 0: + self.zoom_motor_hwobj.move_to_position(1) + gevent.sleep(0.2) # wait for zoom update + else: + self.zoom_motor_hwobj.move_to_position(4) + gevent.sleep(0.2) # wait for motors from previous centrings to start moving + + self.wait_device_ready( timeout = 20) # wait for motors from previous centrings to finish + + #self.logger.debug('find_loop output %s' % str(self.find_loop_xaloc()) ) + + # check if loop is there, if not, search + it = 0 + maxit = 3 + x, y, info, surface_score = self.find_loop_xaloc() + while ( -1 in [x,y]) and it < maxit: + self.logger.debug('-1 in first x,y find_loop output %s, %s' % ( str(x), str(y) ) ) + if not self.search_pin(): + self.userlogger.error("Reached minimal position for omegax, sample cannot be found, aborting centring") + self.phiy_motor_hwobj.set_value(0, timeout = 5 ) + self.cancel_centring_method(True) + return + it += 1 + gevent.sleep(0.1) + x, y, info, surface_score = self.find_loop_xaloc() + else: + if -1 in [x,y]: self.cancel_centring_method() + + # check if loop is past camera, and the pin is seen. If so, first move loop out + it = 0 + image_edge_margin = 100 + while x < image_edge_margin and it < maxit: + self.logger.debug('x < image_edge_margin, x and y from find_loop %s, %s' % ( str(x), str(y) ) ) + self.retreat_pin() + it += 1 + gevent.sleep(0.1) + x, y, info, surface_score = self.find_loop_xaloc() + else: + if ( -1 in [x,y] ) or y < image_edge_margin : self.cancel_centring_method() + + surface_score_list = [] + self.centring_hwobj.initCentringProcedure() + self.logger.debug("self.numCentringImages %d, self.centringAngleRange %d" % \ + (self.numCentringImages, self.centringAngleRange) ) + for image in range( int( self.numCentringImages ) ): + self.logger.debug("self.current_centring_method %s" % self.current_centring_method ) + if self.current_centring_method == None: + self.logger.debug("No centering method selected, cannot continue" ) + break + #self.logger.debug("Harvesting fotos for automatic_centring : x %s, y %s, info %s, surface_score %s" % + #( str(x), str(y), str(info), str(surface_score) ) ) + if x > 0 and y > 0: + self.centring_hwobj.appendCentringDataPoint( + {"X": (x - self.beam_position[0])/ self.pixels_per_mm_x, + "Y": (y - self.beam_position[1])/ self.pixels_per_mm_y}) + surface_score_list.append(surface_score) + # Now rotate and take another point + if image < self.numCentringImages - 1: # Last rotation is not necessary + #self.userlogger.info( "rotating omega" ) + new_pos = self.motor_hwobj_dict['phi'].get_value() + ( self.phi_centring_direction * \ + self.centringAngleRange/ ( self.numCentringImages - 1 ) ) + self.motor_hwobj_dict['phi'].set_value( new_pos, timeout = 5 ) + gevent.sleep(0.01) + self.wait_device_ready( timeout = 15) + x, y, info, surface_score = self.find_loop_xaloc() + #self.omega_reference_add_constraint() + centred_pos_dict = self.centring_hwobj.centeredPosition(return_by_name=False) + self.emit("newAutomaticCentringPoint", centred_pos_dict) + + + #TODO: add the difference between self.motor_hwobj_dict['phiz'] and self.omegaz_reference to centx & centy + vertdist = centred_pos_dict[ self.motor_hwobj_dict['phiz'] ] - self.omegaz_reference + # Fix the omegaz (phiz) motor position to the known center + #self.logger.debug("Calculated phiz %.4f, difference with reference %.4f" % \ + # (centred_pos_dict[ self.motor_hwobj_dict[ 'phiz' ] ] , vertdist ) ) + + dx = 0 + dy = 0 + dx, dy = self.vertical_dist_to_samp_pos (self.phi_motor_hwobj.get_value() , -vertdist) + centred_pos_dict[ self.motor_hwobj_dict['phiz'] ] = self.omegaz_reference + centred_pos_dict[ self.motor_hwobj_dict['sampx'] ] = centred_pos_dict[ self.motor_hwobj_dict['sampx'] ] + dy + centred_pos_dict[ self.motor_hwobj_dict['sampy'] ] = centred_pos_dict[ self.motor_hwobj_dict['sampy'] ] + dx + + #self.logger.debug( "centred_pos_dict %s" % str( centred_pos_dict ) ) + + self.automatic_centring_try_count += 1 + + return centred_pos_dict + + def retreat_pin(self): + self.logger.debug(" moving sample back by half a camera width") + hor_mot_hwobj = self.phiy_motor_hwobj + half_camera_width_mm = HWR.beamline.sample_view.camera.get_width() / self.pixels_per_mm_x / 2 # half camera width in mm + #self.logger.debug( "half camera_width_mm %.4f" % half_camera_width_mm ) + hor_mot_hwobj.set_value( hor_mot_hwobj.get_value() + half_camera_width_mm, timeout = 6 ) + gevent.sleep(0.1) # wait for zoom update + hor_mot_hwobj.wait_end_of_move( timeout = 10 ) + hor_mot_hwobj.wait_ready( timeout = 10 ) + gevent.sleep(0.1) # wait for zoom update + self.logger.debug(" Done moving sample back by half a camera width") + + def search_pin(self): + spindle_mot_hwobj = self.phi_motor_hwobj + hor_mot_hwobj = self.phiy_motor_hwobj + + # Save initial velocity + hor_mot_ini_vel = hor_mot_hwobj.get_velocity() + + # get camera width in mm + camera_width_mm = HWR.beamline.sample_view.camera.get_width() / self.pixels_per_mm_x # full camera width in mm + #self.logger.debug( "camera_width_mm %.4f" % camera_width_mm ) + + #TODO:check the limit of the phiy motor and make relative movement smalle if necessary + relmovdist = 0 + if camera_width_mm > math.fabs( hor_mot_hwobj.get_limits()[0] - hor_mot_hwobj.get_value() ): + relmovdist = math.fabs( hor_mot_hwobj.get_limits()[0] - hor_mot_hwobj.get_value() ) - 0.002 + else: relmovdist = camera_width_mm + if relmovdist < 0.003: return False #omegax at minimum + + # set horizontal motor velocity so that a full camera with can be scanned with 180 deg rotation of spindle axis + time_for_scan = 180 / spindle_mot_hwobj.get_velocity() + 0.01 # in seconds + hor_vel = camera_width_mm / time_for_scan + #self.logger.debug( "Calculated horizontal velocity %.4f" % hor_vel ) + if hor_vel < hor_mot_hwobj.get_velocity(): + if hor_vel < 0.001: hor_vel = 0.001 + else: + hor_mot_hwobj.wait_ready( timeout = 10 ) + hor_mot_hwobj.set_velocity(hor_vel) + + #self.logger.debug( 'hor mot pos channel info %s' % str( hor_mot_hwobj.position_channel.get_info().minval ) ) + #self.logger.debug( 'hor mot limits %s' % str( hor_mot_hwobj.get_limits() ) ) + + # start the motor positions asynchronously + self.logger.debug("Moving omegax relative %s" % relmovdist) + hor_mot_hwobj.set_value( hor_mot_hwobj.get_value() - relmovdist ) + spindle_mot_hwobj.set_value( spindle_mot_hwobj.get_value() + 180 ) + hor_mot_hwobj.wait_end_of_move( timeout = 10 ) + spindle_mot_hwobj.wait_end_of_move( timeout = 10 ) + + # Keep checking the location of the loop. When found, stop the motor movements + stime = time.time() + while time.time() - stime < time_for_scan: + if not ( -1 in self.find_loop_xaloc()[:1] ): + break + gevent.sleep(0.1) + + hor_mot_hwobj.stop() + spindle_mot_hwobj.stop() + gevent.sleep(0.1) + + # reset the velocities + hor_mot_hwobj.set_velocity(hor_mot_ini_vel) + return True + + def motor_positions_to_screen(self, centred_positions_dict): + """ + Descript. : returns the camera pixels of the point corresponding to the given motor positions + """ + c = centred_positions_dict + + #kappa = self.current_motor_positions["kappa"] + #phi = self.current_motor_positions["kappa_phi"] + + kappa = self.motor_hwobj_dict['kappa'].get_value() + phi = self.motor_hwobj_dict['kappa_phi'].get_value() + #IK TODO remove this director call + + # TODO:implement minikappa_correction_hwobj + #if (c['kappa'], c['kappa_phi']) != (kappa, phi) \ + #and self.minikappa_correction_hwobj is not None: + ##c['sampx'], c['sampy'], c['phiy'] + #c['sampx'], c['sampy'], c['phiy'] = self.minikappa_correction_hwobj.shift( + #c['kappa'], c['kappa_phi'], [c['sampx'], c['sampy'], c['phiy']], kappa, phi) + + #TODO: beam_x and beam_y are not part of c? These give difference in beam pos with respect to center + #self.logger.debug('motor_positions_to_screen, zoom_centre x %d, y %d' % \ + #(self.zoom_centre['x'], self.zoom_centre['y']) ) + #self.logger.debug('motor_positions_to_screen, pixels_per_mm_x %d, y %d' % \ + #(self.pixels_per_mm_x, self.pixels_per_mm_y) ) + beam_x = ( self.beam_position[0] - self.zoom_centre['x'] ) / self.pixels_per_mm_x + beam_y = ( self.beam_position[1] - self.zoom_centre['y'] ) / self.pixels_per_mm_y + + xy = self.centring_hwobj.centringToScreen(c) + #self.logger.debug( 'xy dict %s' % str(xy) ) + if xy: + #self.logger.debug( 'xy[\'X\'] %s xy[\'Y\'] %s' % ( xy['X'], xy['Y'] ) ) + x = ( xy['X'] + beam_x ) * self.pixels_per_mm_x + \ + self.zoom_centre['x'] + y = ( xy['Y'] + beam_y ) * self.pixels_per_mm_y + \ + self.zoom_centre['y'] + #self.logger.debug( 'x %4.2f y %4.2f' % ( x, y ) ) + return x, y + + def centring_done(self, centring_procedure): + """ + Descript. : + """ + try: + motor_pos = centring_procedure.get() + if isinstance(motor_pos, gevent.GreenletExit): + raise Exception( str(motor_pos) ) + except: + logging.exception("Could not complete centring") + self.emit_centring_failed() + else: + self.emit_progress_message("Moving sample to centred position...") + self.emit_centring_moving() + + try: + # msg = '' + # for mot, pos in motor_pos.items(): + # msg += '%s = %s\n' % (str(mot.name()), pos) + self.logger.info("Centring finished")#. Moving motors to:\n%s" % msg) + self.move_to_motors_positions(motor_pos, wait=True) + except: + logging.exception("Could not move to centred position") + self.emit_centring_failed() + else: + #if 3 click centring move -180. well. dont, in principle the calculated + # centred positions include omega to initial position + pass + #if not self.in_plate_mode(): + # logging.getLogger("HWR").debug("Centring finished. Moving omega back to initial position") + # self.motor_hwobj_dict['phi'].set_value(self.motor_hwobj_dict['phi'].get_value() - 180, timeout = 4 ) + # logging.getLogger("HWR").debug(" Moving omega done") + + #if self.current_centring_method == GenericDiffractometer.CENTRING_METHOD_AUTO: + # self.emit("newAutomaticCentringPoint", motor_pos) + self.ready_event.set() + self.centring_time = time.time() + self.update_centring_status(motor_pos) + if ( self.current_centring_method == GenericDiffractometer.CENTRING_METHOD_AUTO and \ + self.automatic_centring_try_count == self.numAutoCentringCycles ) or \ + self.current_centring_method != GenericDiffractometer.CENTRING_METHOD_AUTO: + self.userlogger.info( "Centring finished" ) + self.emit_centring_successful() + self.emit_progress_message("") + + def update_centring_status(self, motor_pos): + curr_time = time.strftime("%Y-%m-%d %H:%M:%S") + self.centring_status["endTime"] = curr_time + self.centring_status["motors"] = self.convert_from_obj_to_name(motor_pos) + self.centring_status["method"] = self.current_centring_method + self.centring_status["valid"] = True + + def emit_centring_successful(self): """ Descript. : """ + method = self.current_centring_method + self.emit('centringSuccessful', (method, self.get_centring_status())) + self.current_centring_method = None + self.current_centring_procedure = None + + def find_loop_xaloc(self): + """ + Description: finds loop using lucid3 + An example filename can be found at /tmp/mxcube_sample_snapshot.png + """ + + # the following lines are used because the lucid3 package installed at xaloc + # does not allow an array as argument. Lucid3 should be updated to use the code below + #self.logger.debug("starting find_loop") + #snapshot_filename = os.path.join(tempfile.gettempdir(), "mxcube_sample_snapshot.png") + #image_array = HWR.beamline.sample_view.camera.get_snapshot(return_as_array=True) + ## Now flip the image and convert to PIL type image + #im = Image.fromarray( np.fliplr( image_array ) ) + #im.save( snapshot_filename ) + ##self.logger.debug("in find_loop: snapshot_filename is %s" % snapshot_filename) + #(info, x, y) = lucid.find_loop( snapshot_filename , IterationClosing=6 ) + #self.logger.debug('Lucid output: info %s x %s y %s' % ( str(info), str(x), str(y) ) ) + + + #================================================================================= + + #the following lines should be used when lucid3 is updated to the newest version + image_array = HWR.beamline.sample_view.camera.get_snapshot(return_as_array=True) + #self.logger.debug("image_array: %s" % str(image_array)) + #self.logger.debug("type( image_array ): %s" % str( type(image_array) ) ) + if type( image_array ) == str: self.logger.debug("image_array is a string" ) + image_array = np.fliplr( image_array ) + (info, x, y) = lucid.find_loop( image_array , IterationClosing=6 ) + #self.logger.debug('Lucid output: info %s x %s y %s' % ( str(info), str(x), str(y) ) ) + + #================================================================================= + + #self.logger.debug("find_loop output : info %s, x %s, y %s" % ( str(info), str(x), str(y) ) ) + if x > 0 and y > 0: + x = 900 - x + + surface_score = 10 + return x, y, info, surface_score + + def prepare_centring(self): + """ + Prepare beamline for to sample_view phase. + """ + + self.saved_zoom_pos = self.zoom_motor_hwobj.get_value() + + if self.get_current_phase().upper() != "SAMPLE": + self.logger.info("Not in sample view phase. Asking diff to go") + self.wait_ready() + self.set_diff_phase('Centring') # call diffcentring phase to prepare diff for centring + # TODO: workaround to set omega velocity to 60 + try: + self.phi_motor_hwobj.set_velocity(60) + except: + self.logger.error("Cannot apply workaround for omega velocity") + # TODO: dynamic omegaz_reference + if self.omegaz_reference_channel != None: + if self.use_sample_centring: self.centring_phiz.reference_position = self.omegaz_reference_channel.get_value() + self.omegaz_reference = self.omegaz_reference_channel.get_value() + + if self.phi_motor_hwobj.get_value() > 0: self.phi_centring_direction = -1 + else: self.phi_centring_direction = 1 + + return True + + def omega_reference_add_constraint(self): + """ + Descript. : WHAT DOES THIS DO? + """ + if self.omega_reference_par is None or self.beam_position is None: + return + if self.omega_reference_par["camera_axis"].lower() == "x": + on_beam = (self.beam_position[0] - self.zoom_centre['x']) * \ + self.omega_reference_par["direction"] / self.pixels_per_mm_x + \ + self.omega_reference_par["position"] + else: + on_beam = (self.beam_position[1] - self.zoom_centre['y']) * \ + self.omega_reference_par["direction"] / self.pixels_per_mm_y + \ + self.omega_reference_par["position"] + self.centring_hwobj.appendMotorConstraint(self.omega_reference_motor, on_beam) + + def move_to_motors_positions(self, motors_positions, wait=False): + """ + """ + self.emit_progress_message("Moving to motors positions...") + self.move_to_motors_positions_procedure = gevent.spawn(\ + self.move_motors, motors_positions) + self.move_to_motors_positions_procedure.link(self.move_motors_done) + if wait: + self.wait_device_not_ready( timeout = 50 ) + self.wait_device_ready( timeout = 10 ) + + def move_motors(self, motor_positions, timeout=15): + """ + Moves diffractometer motors to the requested positions + + :param motors_dict: dictionary with motor names or hwobj + and target values. + :type motors_dict: dict + + Reimplemented to improve error messaging () + """ + if not isinstance(motor_positions, dict): + motor_positions = motor_positions.as_dict() + + try: + self.wait_device_ready( timeout = timeout) + except Exception as e: + self.userlogger.error( str(e) ) + raise(e) + + for motor in motor_positions.keys(): + position = motor_positions[motor] + """ + if isinstance(motor, (str, unicode)): + logging.getLogger("HWR").debug(" Moving %s to %s" % (motor, position)) + else: + logging.getLogger("HWR").debug( + " Moving %s to %s" % (str(motor.name()), position) + ) + """ + if isinstance(motor, (str, unicode)): + motor_role = motor + motor = self.motor_hwobj_dict.get(motor_role) + # del motor_positions[motor_role] + if None in (motor, position): + continue + # motor_positions[motor] = position + motor.set_value(position) + self.wait_device_ready(timeout) + + if self.delay_state_polling is not None and self.delay_state_polling > 0: + # delay polling for state in the + # case of controller not reporting MOVING inmediately after cmd + gevent.sleep(self.delay_state_polling) + + self.wait_device_ready( timeout = timeout) + + + + def get_grid_direction(self): + + grid_direction = self.get_property("gridDirection") + + grid_direction = {} + self.grid_direction['omega_ref'] = 1 + self.grid_direction['fast'] = [ 1, 0 ] # Qt4_GraphicsLib.py line 1184/85 MD2 + self.grid_direction['slow'] = [ 0, -1 ] # Qt4_GraphicsLib.py line 1184/85 MD2 + self.logger.info('diffr_hwobj grid_direction %s' % self.grid_direction) + + return self.grid_direction + + # TODO: Review override current_state by current_phase + def phase_changed(self, phase): + """ + Emit stateChanged signal according to supervisor current phase. + """ + #self.current_phase = phase + self.emit('minidiffPhaseChanged', (phase, )) + + def phi_motor_moved(self, pos): + """ + Emit phiMotorMoved signal with position value. + """ self.current_motor_positions["phi"] = pos - self.emit_diffractometer_moved() self.emit("phiMotorMoved", pos) - # self.emit('stateChanged', (self.current_motor_states["phi"], )) def phi_motor_state_changed(self, state): """ - Descript. : + Emit stateChanged signal with state value. """ - self.current_motor_states["phi"] = state - self.emit("stateChanged", (state,)) + self.emit('stateChanged', (state, )) def phiz_motor_moved(self, pos): """ - Descript. : """ self.current_motor_positions["phiz"] = pos - if time.time() - self.centring_time > 1.0: - self.invalidate_centring() - self.emit_diffractometer_moved() def phiz_motor_state_changed(self, state): """ - Descript. : + Emit stateChanged signal with state value. """ - self.emit("stateChanged", (state,)) + self.emit('stateChanged', (state, )) def phiy_motor_state_changed(self, state): """ - Descript. : + Emit stateChanged signal with state value. """ - self.emit("stateChanged", (state,)) + self.emit('stateChanged', (state, )) def phiy_motor_moved(self, pos): """ - Descript. : """ self.current_motor_positions["phiy"] = pos - if time.time() - self.centring_time > 1.0: - self.invalidate_centring() - self.emit_diffractometer_moved() def zoom_position_changed(self, value): + """ + Update positions after zoom changed. + + @value: zoom position. + """ + #self.logger.debug("zoom position changed") self.update_pixels_per_mm() self.current_motor_positions["zoom"] = value - self.refresh_omega_reference_position() def zoom_motor_predefined_position_changed(self, position_name, offset): """ - Descript. : + Update pixel size and emit signal. """ + #self.logger.debug("zoom predefined position changed") self.update_pixels_per_mm() - self.emit("zoomMotorPredefinedPositionChanged", (position_name, offset)) + self.emit('zoomMotorPredefinedPositionChanged', + (position_name, offset, )) def zoom_motor_state_changed(self, state): """ - Descript. : + Emit signal for motor zoom changed + + @state: new state value to emit. """ - self.emit("stateChanged", (state,)) + self.emit('stateChanged', (state, )) def sampleX_motor_moved(self, pos): """ - Descript. : """ self.current_motor_positions["sampx"] = pos - if time.time() - self.centring_time > 1.0: - self.invalidate_centring() - self.emit_diffractometer_moved() def sampleX_motor_state_changed(self, state): """ - Descript. : + Emit stateChanged signal with state value. """ self.current_motor_states["sampx"] = state - self.emit("stateChanged", (state,)) + self.emit('stateChanged', (state, )) def sampleY_motor_moved(self, pos): """ - Descript. : """ self.current_motor_positions["sampy"] = pos - if time.time() - self.centring_time > 1.0: - self.invalidate_centring() - self.emit_diffractometer_moved() def sampleY_motor_state_changed(self, state): """ - Descript. : + Emit stateChanged signal with state value. """ self.current_motor_states["sampy"] = state - self.emit("stateChanged", (state,)) + self.emit('stateChanged', (state, )) + + def kappa_motor_moved(self, pos): + """ + Emit kappaMotorMoved signal with position value. + """ + self.current_motor_positions["kappa"] = pos + self.emit("kappaMotorMoved", pos) + + def kappa_motor_state_changed(self, state): + """ + Emit stateChanged signal with state value. + """ + self.current_motor_states["kappa"] = state + self.emit('stateChanged', (state, )) + + def kappa_phi_motor_moved(self, pos): + """ + Emit kappa_phiMotorMoved signal with position value. + """ + self.current_motor_positions["kappa_phi"] = pos + self.emit("kappa_phiMotorMoved", pos) + + def kappa_phi_motor_state_changed(self, state): + """ + Emit stateChanged signal with state value. + """ + self.current_motor_states["kappa_phi"] = state + self.emit('stateChanged', (state, )) def focus_motor_moved(self, pos): """ - Descript. : """ self.current_motor_positions["focus"] = pos def start_auto_focus(self): - self.cmd_start_auto_focus() + pass + + def move_omega(self, pos, velocity=None): + """ + Move omega to absolute position. + + @pos: target position + """ + # turn it on + if velocity is not None: + self.phi_motor_hwobj.set_velocity(velocity) + self.phi_motor_hwobj.set_value(pos) + time.sleep(0.2) + # it should wait here + + def move_omega_relative(self, relpos): + """ + Move omega to relative position. + + @relpos: target relative position + """ + #TODO:Are all these waiting times really necessary??' + self.wait_device_ready() + self.phi_motor_hwobj.set_value( self.phi_motor_hwobj.get_value() + relpos, timeout = 10 ) + time.sleep(0.2) + self.wait_device_ready() + + def set_diff_phase(self, phase, timeout=None): + """ + General function to set phase by using supervisor commands. + CAUTION: setting the diff phase does not change the position of: + - the detector cover + - the position of the fast shutter. + It is better to use the supervisor phases for safety reasons + """ + if phase.upper() != "TRANSFER" and HWR.beamline.ln2shower.is_pumping(): + msg = "Cannot change to non transfer phase when the lnshower is pumping, turn off the shower first" + self.userlogger.error(msg) + raise Exception(msg) + if phase.upper() == "TRANSFER": + self.go_transfer() + #elif phase.upper() == "COLLECT": + #self.go_collect() + #elif phase.upper() == "BEAMVIEW": + #self.go_beam_view() + elif phase.upper() == "CENTRING": + self.go_sample_view() + else: + self.logger.warning( + "Diffractometer set_phase asked for un-handled phase: %s" % phase + ) + return + + self.logger.debug( + "Telling diff to go to phase %s, with timeout %s" % ( phase, timeout ) + ) + + if timeout: + time.sleep(1) + self.wait_ready( timeout = timeout ) + time.sleep(1) + self.logger.debug( + "Diff phase is %s" % ( self.get_current_phase() ) + ) + + # Copied from GenericDiffractometer just to improve error loggin + def wait_device_ready(self, timeout=30): + """ Waits when diffractometer status is ready: + + :param timeout: timeout in second + :type timeout: int + """ + gevent.sleep(1) # wait a bit to see if state does not change inmediately + with gevent.Timeout(timeout, Exception("Timeout waiting for Diffracometer ready, check bl13/eh/diff. Is omegax close enough to 0??")): + while not self.is_ready(): + time.sleep(0.01) + + def go_transfer(self): + self.cmd_go_transfer() + + def go_sample_view(self): + self.cmd_go_sample_view() + + # TODO: move to supervisor + def get_current_phase(self): + """ + Descript. : read diff phase + """ + try: + _value = self.chan_phase.get_value() + #self.logger.debug('get_current_phase: (value={0}, type={1})'.format(_value, type(_value))) + except Exception as e: + raise RuntimeError('Cannot get diff current phase:\n%s, try to restart the diff DS' % str(e)) + return _value + # return self.chan_phase.get_value() + +def test_hwo(hwo): + print(hwo.get_phase_list()) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocOfflineProcessing.py b/mxcubecore/HardwareObjects/ALBA/XalocOfflineProcessing.py new file mode 100755 index 0000000000..8f9c76ef8f --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocOfflineProcessing.py @@ -0,0 +1,404 @@ +# +# 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 . + +""" +[Name] +XalocOfflineProcessing + +[Description] +Hardware Object used to prepare and start the autoprocessing +pipelines for ALBA beamlines. + +[Emitted signals] +- None + +TODO: the same xml input files can be used for different processing +TODO: implement small mol processing +""" + +from __future__ import print_function + +import os +import math +import logging + +from mxcubecore.BaseHardwareObjects import HardwareObject +from XSDataCommon import XSDataBoolean, XSDataFile, XSDataString, XSDataInteger, XSDataDouble +from XalocXSDataAutoprocv1_0 import XalocXSDataAutoprocInput +from XalocXSDataControlAutoPROCv1_1 import XSDataInputControlAutoPROC +from XalocXSDataControlXia2DIALSv1_0 import XalocXSDataInputXia2DIALS + +__credits__ = ["ALBA Synchrotron"] +__version__ = "3" +__category__ = "General" + + +class XalocOfflineProcessing(HardwareObject): + def __init__(self, name): + HardwareObject.__init__(self, name) + self.logger = logging.getLogger("HWR.XalocOfflineProcessing") + self.template_dir = None + self.detsamdis_hwobj = None + self.chan_beamx = None + self.chan_beamy = None + self.ednaproc_input_file = None + self.autoproc_input_file = None + self.cluster = None + self.sample_is_small_molecule = False + + def init(self): + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + self.template_dir = self.get_property("template_dir") + self.logger.debug("Autoprocessing template_dir = %s" % + self.template_dir) + # TODO: include these values in dc_pars or osc_seq dictionaries + self.detsamdis_hwobj = self.get_object_by_role("detector_distance") + self.chan_beamx = self.get_channel_object('beamx') + self.chan_beamy = self.get_channel_object('beamy') + + self.cluster = self.get_object_by_role("cluster") + + def create_input_files(self, dc_pars): + + self.logger.debug("XalocOfflineProcessing create_input_files dc_pars = %s " % dc_pars ) + xds_dir = dc_pars['xds_dir'] + mosflm_dir = dc_pars['mosflm_dir'] + ednaproc_dir = dc_pars['ednaproc_dir'] + autoproc_dir = dc_pars['autoproc_dir'] + + fileinfo = dc_pars['fileinfo'] + osc_seq = dc_pars['oscillation_sequence'][0] + + prefix = fileinfo['prefix'] + runno = fileinfo['run_number'] + + exp_time = osc_seq['exposure_time'] + + # start_angle = osc_seq['start'] + nb_images = osc_seq['number_of_images'] + start_img_num = osc_seq['start_image_number'] + angle_increment = osc_seq['range'] + + wavelength = osc_seq.get('wavelength', 0) + + xds_template_name = 'XDS_TEMPLATE.INP' + mosflm_template_name = 'mosflm_template.dat' + + xds_template_path = os.path.join(self.template_dir, xds_template_name) + mosflm_template_path = os.path.join(self.template_dir, mosflm_template_name) + + xds_file = os.path.join(xds_dir, "XDS.INP") + mosflm_file = os.path.join(mosflm_dir, "mosflm.dat") + + # PREPARE VARIABLES + detsamdis = self.detsamdis_hwobj.get_value() + beamx, beamy = self.chan_beamx.get_value(), self.chan_beamy.get_value() + + mbeamx, mbeamy = beamy * 0.172, beamx * 0.172 + + data_range_start_num = start_img_num + data_range_finish_num = start_img_num + nb_images - 1 + background_range_start_num = start_img_num + spot_range_start_num = start_img_num + minimum_range = 0 + background_range_finish_num = 0 + spot_range_finish_num = 0 + + if angle_increment != 0: + minimum_range = int(round(20 / angle_increment)) + elif angle_increment == 0: + minimum_range = 1 + if nb_images >= minimum_range: + background_range_finish_num = start_img_num + minimum_range - 1 + if nb_images >= minimum_range: + spot_range_finish_num = start_img_num + minimum_range - 1 + if nb_images < minimum_range: + background_range_finish_num = start_img_num + nb_images - 1 + if nb_images < minimum_range: + spot_range_finish_num = start_img_num + nb_images - 1 + + test_low_res = 8. + largest_vector = 0.172 * ((max(beamx, 2463 - beamx))**2 + + (max(beamy, 2527 - beamy))**2)**0.5 + test_high_res = round(wavelength / (2 * math.sin(0.5 * math.atan( + largest_vector / detsamdis))), 2) + low_res = 50. + high_res = test_high_res + data_filename = prefix + '_' + str(runno) + '_????' + mdata_filename = prefix + '_' + str(runno) + '_####.cbf' + seconds = 5 * exp_time + + if angle_increment < 1 and not angle_increment == 0: + seconds = 5 * exp_time / angle_increment + + # DEFINE SG/UNIT CELL + spacegroup_number = '' + unit_cell_constants = '' + + #datapath_dir = os.path.abspath(xds_file).replace('PROCESS_DATA', 'RAW_DATA') + #datapath_dir = os.path.dirname(os.path.dirname(datapath_dir)) + os.path.sep + datapath_dir = fileinfo['directory']+ os.path.sep + + # CREATE XDS.INP FILE + xds_templ = open(xds_template_path, "r").read() + + xds_templ = xds_templ.replace('###BEAMX###', str(round(beamx, 2))) + xds_templ = xds_templ.replace("###BEAMY###", str(round(beamy, 2))) + xds_templ = xds_templ.replace("###DETSAMDIS###", str(round(detsamdis, 2))) + xds_templ = xds_templ.replace("###ANGLEINCREMENT###", str(angle_increment)) + xds_templ = xds_templ.replace("###WAVELENGTH###", str(wavelength)) + xds_templ = xds_templ.replace("###DATARANGESTARTNUM###", + str(data_range_start_num)) + xds_templ = xds_templ.replace("###DATARANGEFINISHNUM###", + str(data_range_finish_num)) + xds_templ = xds_templ.replace("###BACKGROUNDRANGESTART###", + str(background_range_start_num)) + xds_templ = xds_templ.replace("###BACKGROUNDRANGEFINISHNUM###", + str(background_range_finish_num)) + xds_templ = xds_templ.replace("###SPOTRANGESTARTNUM###", + str(spot_range_start_num)) + xds_templ = xds_templ.replace("###SPOTRANGEFINISHNUM###", + str(spot_range_finish_num)) + xds_templ = xds_templ.replace("###TESTLOWRES###", str(test_low_res)) + xds_templ = xds_templ.replace("###TESTHIGHRES###", str(test_high_res)) + xds_templ = xds_templ.replace("###LOWRES###", str(low_res)) + xds_templ = xds_templ.replace("###HIGHRES###", str(high_res)) + xds_templ = xds_templ.replace("###DIRECTORY###", str(datapath_dir)) + xds_templ = xds_templ.replace("###FILENAME###", str(data_filename)) + xds_templ = xds_templ.replace("###SECONDS###", str(int(seconds))) + xds_templ = xds_templ.replace("###LYSOZYME_SPACE_GROUP_NUMBER###", + str(spacegroup_number)) + xds_templ = xds_templ.replace("###LYSOZYME_UNIT_CELL_CONSTANTS###", + str(unit_cell_constants)) + + open(xds_file, "w").write(xds_templ) + + # CREATE MOSFLM.DAT FILE + mosflm_templ = open(mosflm_template_path, "r").read() + + mosflm_templ = mosflm_templ.replace("###DETSAMDIS###", str(round(detsamdis, 2))) + mosflm_templ = mosflm_templ.replace('###BEAMX###', str(round(mbeamx, 2))) + mosflm_templ = mosflm_templ.replace("###BEAMY###", str(round(mbeamy, 2))) + mosflm_templ = mosflm_templ.replace("###DIRECTORY###", str(datapath_dir)) + mosflm_templ = mosflm_templ.replace("###FILENAME###", str(mdata_filename)) + mosflm_templ = mosflm_templ.replace("###WAVELENGTH###", str(wavelength)) + mosflm_templ = mosflm_templ.replace("###DATARANGESTARTNUM###", + str(data_range_start_num)) + + open(mosflm_file, "w").write(mosflm_templ) + + # CREATE EDNAPROC XML FILE + collection_id = dc_pars['collection_id'] + ednaproc_dir = dc_pars['ednaproc_dir'] + + ednaproc_input_file = os.path.join(ednaproc_dir, "EDNAprocInput_%d.xml" % + collection_id) + ednaproc_input = XalocXSDataAutoprocInput() + + input_file = XSDataFile() + path = XSDataString() + path.setValue(xds_file) + input_file.setPath(path) + + ednaproc_input.setInput_file(input_file) + ednaproc_input.setData_collection_id(XSDataInteger(collection_id)) + + ednaproc_input.setDoAnomAndNonanom(XSDataBoolean(True)) + ednaproc_input = self.add_user_input_to_xml(ednaproc_input, dc_pars) + + ednaproc_input.exportToFile(ednaproc_input_file) + self.ednaproc_input_file = ednaproc_input_file + + # CREATE AUTOPROC XML FILE + self.create_autoproc_edna_input_file(dc_pars, data_range_start_num, data_range_finish_num, mdata_filename) + self.create_xia2_edna_input_file(dc_pars, data_range_start_num, data_range_finish_num, mdata_filename) + self.create_xia2chem_edna_input_file(dc_pars, data_range_start_num, data_range_finish_num, mdata_filename) + + def create_autoproc_edna_input_file(self, dc_pars, fromN, toN, template, ispyb=True): + + # Get data from data collection parameters + collection_id = dc_pars['collection_id'] + images_dir = dc_pars['fileinfo']['directory'] + template = template + first_image_nb = fromN + last_image_nb = toN + output_dir = dc_pars['autoproc_dir'] + + autoproc_input = XSDataInputControlAutoPROC() + #autoproc_input = XalocXSDataInputControlAutoPROC() + # Do both anom and no anom + autoproc_input.setDoAnomAndNonanom(XSDataBoolean(True)) + # Add specific configuration file by the slurm script + try: + autoproc_input.setConfigDef(XSDataFile(XSDataString("__configDef"))) + #self.logger.debug("Setting configDef path" ) + except Exception as e: + self.logger.debug("XalocOfflineProcessing Cant set configDef file for AutoPROC processing" ) + self.logger.debug("Error %s" % e) + + if ispyb: + autoproc_input.setDataCollectionId(XSDataInteger(collection_id)) + else: + autoproc_input.setDirN(XSDataFile(XSDataString(images_dir))) + autoproc_input.setFromN(XSDataInteger(first_image_nb)) + autoproc_input.setToN(XSDataInteger(last_image_nb)) + autoproc_input.setTemplateN(XSDataString(template)) + + # When the user does not give a cell, the cell parameters are set to 0, + # the EDNA autoproc plugin does not accept this + # TODO: dont add cell parameters unless specified by the user + autoproc_input = self.add_user_input_to_xml(autoproc_input, dc_pars) + autoproc_input.setDoAnomAndNonanom(XSDataBoolean(True)) + + # Export file + autoproc_input_filename = os.path.join(output_dir, + "AutoPROCInput_%d.xml" % collection_id) + autoproc_input.exportToFile(autoproc_input_filename) + self.autoproc_input_file = autoproc_input_filename + + def create_xia2_edna_input_file(self, dc_pars, fromN, toN, template, ispyb=True): + collection_id = dc_pars['collection_id'] + images_dir = dc_pars['fileinfo']['directory'] + template = template + first_image_nb = fromN + last_image_nb = toN + output_dir = dc_pars['xia2_dir'] + first_image_string = os.path.join(images_dir,template.replace('####',"%04d" % first_image_nb)) + + # Create EDNA data model input file + xia2_input = XalocXSDataInputXia2DIALS() + xia2_input.setDoAnomAndNonanom(XSDataBoolean(True)) + + if ispyb: + xia2_input.setDiffractionImage(XSDataString(first_image_string)) + xia2_input.setDataCollectionId(XSDataInteger(collection_id)) + else: + raise NotImplementedError("Cannot process with XIA2 without using ISPyB") + + xia2_input = self.add_user_input_to_xml(xia2_input, dc_pars) + + # Export file + xia2_input_filename = os.path.join(output_dir, "XIA2Input_%d.xml" % collection_id) + xia2_input.exportToFile(xia2_input_filename) + self.xia2_input_file = xia2_input_filename + + def create_xia2chem_edna_input_file(self, dc_pars, fromN, toN, template, ispyb=True): + collection_id = dc_pars['collection_id'] + images_dir = dc_pars['fileinfo']['directory'] + template = template + first_image_nb = fromN + last_image_nb = toN + output_dir = dc_pars['xia2chem_dir'] + first_image_string = os.path.join(images_dir,template.replace('####',"%04d" % first_image_nb)) + + # Create EDNA data model input file + xia2_input = XalocXSDataInputXia2DIALS() + xia2_input.setDoAnomAndNonanom(XSDataBoolean(True)) + + if ispyb: + xia2_input.setDiffractionImage(XSDataString(first_image_string)) + xia2_input.setDataCollectionId(XSDataInteger(collection_id)) + else: + raise NotImplementedError("Cannot process with XIA2 chem without using ISPyB") + #xia2_input = self.add_user_input_to_xml(xia2_input, dc_pars) + + detsamdis = self.detsamdis_hwobj.get_value() + osc_seq = dc_pars['oscillation_sequence'][0] + wavelength = osc_seq.get('wavelength', 0) + beamx, beamy = self.chan_beamx.get_value(), self.chan_beamy.get_value() + largest_vector = 0.172 * ((max(beamx, 2463 - beamx))**2 + + (max(beamy, 2527 - beamy))**2)**0.5 + + max_det_res = round(wavelength / (2 * math.sin(0.5 * math.atan( + largest_vector / detsamdis))), 2) + max_det_res = dc_pars['resolution']['upper'] + + xia2_input.setDetector_max_res( XSDataDouble(max_det_res) ) + xia2_input.set_small_molecule_3dii( XSDataBoolean(True) ) + + # Export file + xia2_input_filename = os.path.join(output_dir, "XIA2Input_%d.xml" % collection_id) + xia2_input.exportToFile(xia2_input_filename) + self.xia2chem_input_file = xia2_input_filename + + def add_user_input_to_xml(self, xsd_autoproc_input, params): + #residues_num = float(params.get("residues", 0)) + # These lines are not compatible with the GP AutoPROC module + #if residues_num != 0: + #xsd_autoproc_input.setNres(XSDataDouble(residues_num)) + space_group = params.get("sample_reference").get("spacegroup", "") + if not isinstance(space_group, int) and len(space_group) > 0: + xsd_autoproc_input.setSpacegroup(XSDataString(space_group)) + unit_cell = params.get("sample_reference").get("cell", "") + #if len(unit_cell) > 0: + #xsd_autoproc_input.setUnit_cell(XSDataString(unit_cell)) + return xsd_autoproc_input + + def trigger_auto_processing(self, dc_pars): + + dc_id = dc_pars['collection_id'] + self.logger.debug("Collection_id = %s " % dc_id) + + # EDNAProc + ednaproc_dir = dc_pars['ednaproc_dir'] + logging.getLogger('user_level_log').info("Trigger EDNAProc processing") + job = self.cluster.create_ednaproc_job(dc_id, self.ednaproc_input_file, ednaproc_dir) + ##job.run() + self.cluster.run(job) + self.logger.debug("EDNAProc input file = %s " % self.ednaproc_input_file) + self.logger.debug("Output dir = %s " % ednaproc_dir) + logging.getLogger('user_level_log').info("EDNAProc job ID: %s" % job.id) + + # AutoPROC + autoproc_dir = dc_pars['autoproc_dir'] + logging.getLogger('user_level_log').info("Trigger AutoPROC processing") + job = self.cluster.create_autoproc_job(dc_id, self.autoproc_input_file, autoproc_dir) + self.logger.debug("AutoPROC input file = %s " % self.autoproc_input_file) + ##job.run() + self.cluster.run(job) + self.logger.debug("Output dir = %s " % autoproc_dir) + logging.getLogger('user_level_log').info("AutoPROC job ID: %s" % job.id) + + # XIA2 + xia2_dir = dc_pars['xia2_dir'] + logging.getLogger('user_level_log').info("Trigger XIA2 processing") + job = self.cluster.create_xia2_job(dc_id, self.xia2_input_file, xia2_dir) + self.cluster.run(job) + self.logger.debug("XIA2 input file = %s " % self.xia2_input_file) + self.logger.debug("Output dir = %s " % xia2_dir) + logging.getLogger('user_level_log').info("XIA2 job ID: %s" % job.id) + + # XIA2 small molecule + xia2chem_dir = dc_pars['xia2chem_dir'] + logging.getLogger('user_level_log').info("Trigger XIA2 small molecule processing") + job = self.cluster.create_xia2_job(dc_id, self.xia2chem_input_file, xia2chem_dir) + self.cluster.run(job) + self.logger.debug("XIA2 input file = %s " % self.xia2chem_input_file) + self.logger.debug("Output dir = %s " % xia2chem_dir) + logging.getLogger('user_level_log').info("XIA2 job ID: %s" % job.id) + + def set_sample_type(self, is_small_molecule): + is_small_bool = True + if is_small_molecule == 0: is_small_bool = False + + logging.getLogger('user_level_log').info("Setting sample is small molecule to %s" % is_small_bool) + self.sample_is_small_molecule = is_small_bool + +def test_hwo(hwo): + pass diff --git a/mxcubecore/HardwareObjects/ALBA/XalocOnlineProcessing.py b/mxcubecore/HardwareObjects/ALBA/XalocOnlineProcessing.py new file mode 100755 index 0000000000..eabe9533d5 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocOnlineProcessing.py @@ -0,0 +1,641 @@ +# +# 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 . + +import os +import time +import gevent +import logging +import subprocess + +from mxcubecore.HardwareObjects.DozorOnlineProcessing import ( + DozorOnlineProcessing, +) +from mxcubecore.HardwareObjects.abstract.AbstractOnlineProcessing import ( + AbstractOnlineProcessing, +) + +from XSDataCommon import XSDataBoolean +from XSDataCommon import XSDataDouble +from XSDataCommon import XSDataFloat +from XSDataCommon import XSDataInteger +from XSDataCommon import XSDataString + +import numpy + +from scipy import ndimage +from scipy.interpolate import UnivariateSpline + +from mxcubecore import HardwareRepository as HWR + +__credits__ = ["ALBA Synchrotron"] +__licence__ = "LGPLv3+" +__version__ = "3" +__category__ = "General" + +class XalocOnlineProcessing(DozorOnlineProcessing): + def __init__(self, name): + DozorOnlineProcessing.__init__(self, name) + self.logger = logging.getLogger("HWR.XalocOnlineProcessing") + self.pop_object = None # the subprocess.Popen object returned by subprocess.Popen + self.testing = None + + def init(self): + DozorOnlineProcessing.init(self) + self.testing = self.get_property('testing', False) + + def run_processing(self, data_collection): + """Starts parallel processing + + :param: data_collection: data collection obj, not used, set in queue_entry + :type: data_collection: queue_model_objects.DataCollection + + """ + #self.data_collection = data_collection + #self.logger.debug("data_collection %s" % str(data_collection) ) + #self.prepare_processing() + + input_filename = self.get_input_filename(self.data_collection) + if not input_filename: + input_filename = os.path.join( + self.params_dict["process_directory"], "dozor_input.xml" + ) + + self.create_processing_input_file1_1(input_filename) + + # results = {"raw" : self.results_raw, + # "aligned": self.results_aligned} + # print "emit ! ", results + # self.emit("processingStarted", (data_collection, results)) + # self.emit("processingResultsUpdate", False) + + if not os.path.isfile(self.start_command): + msg = ( + "ParallelProcessing: Start command %s" % self.start_command + + "is not executable" + ) + self.logger.error(msg) + self.set_processing_status("Failed") + else: + #TODO: it can be something more complex than a script file + line_to_execute = ( + self.start_command + + " " + + input_filename + #+ " " + #+ self.params_dict["process_directory"] + ) + + line_to_execute = ( + 'ssh opbl13@ctbl1301 \"' + + line_to_execute + + '\" ' + ) + self.logger.debug("Processing DOZOR with command: %s" % line_to_execute) + + self.started = True + self.pop_object = subprocess.Popen( + str(line_to_execute), + shell=True, +# stdin=None, +# stdout=None, +# stderr=None, +# close_fds=True, + ) + + def create_processing_input_file1_1(self, processing_input_filename): + """Creates dozor input file base on data collection parameters + + :param processing_input_filename + :type : str + """ + from XSDataControlDozorv1_1 import XSDataInputControlDozor + from XSDataControlDozorv1_1 import XSDataResultControlDozor + from XSDataControlDozorv1_1 import XSDataControlImageDozor + + self.logger.debug('Creating Dozor input file %s' % processing_input_filename ) + + input_file = XSDataInputControlDozor() + input_file.setTemplate(XSDataString(self.params_dict["template"])) + input_file.setFirst_image_number(XSDataInteger(self.params_dict["first_image_num"])) + input_file.setLast_image_number(XSDataInteger(self.params_dict["images_num"])) + input_file.setFirst_run_number(XSDataInteger(self.params_dict["run_number"])) + input_file.setLast_run_number(XSDataInteger(self.params_dict["run_number"])) + input_file.setLine_number_of(XSDataInteger(self.params_dict["lines_num"])) + input_file.setReversing_rotation( + XSDataBoolean(self.params_dict["reversing_rotation"]) + ) + pixel_size = HWR.beamline.detector.get_pixel_size() + input_file.setPixelMin(XSDataInteger(pixel_size[0])) + input_file.setPixelMax(XSDataInteger(pixel_size[1])) + #input_file.setPixelMin(XSDataInteger(HWR.beamline.detector.get_pixel_min())) + #input_file.setPixelMax(XSDataInteger(HWR.beamline.detector.get_pixel_max())) + #input_file.setBeamstopSize(XSDataDouble(self.beamstop_hwobj.get_size())) + #input_file.setBeamstopDistance(XSDataDouble(self.beamstop_hwobj.get_distance())) + #input_file.setBeamstopDirection(XSDataString(self.beamstop_hwobj.get_direction())) + + input_file.exportToFile(processing_input_filename) + + def create_processing_input_file1_0(self, processing_input_filename): + """Creates dozor input file base on data collection parameters using version 1_0 + + :param processing_input_filename + :type : str + """ + from XalocXSDataControlDozorv1_0 import XSDataInputControlDozor + from XalocXSDataControlDozorv1_0 import XSDataResultControlDozor + from XalocXSDataControlDozorv1_0 import XSDataControlImageDozor + + self.logger.debug('Creating Dozor input file %s' % processing_input_filename ) + self.logger.debug('Data collection id %d' % self.params_dict["collection_id"] ) + + input_file = XSDataInputControlDozor() + input_file.setDataCollectionId( + XSDataInteger( + self.params_dict["collection_id"] + ) + ) + input_file.setDoISPyBUpload( + XSDataBoolean(True) + ) + input_file.setBatchSize( XSDataInteger(self.params_dict["images_per_line"]) ) + #input_file.setFirst_image_number(XSDataInteger(self.params_dict["first_image_num"])) + #input_file.setLast_image_number(XSDataInteger(self.params_dict["images_num"])) + #input_file.setFirst_run_number(XSDataInteger(self.params_dict["run_number"])) + #input_file.setLast_run_number(XSDataInteger(self.params_dict["run_number"])) + #input_file.setLine_number_of(XSDataInteger(self.params_dict["lines_num"])) + #input_file.setReversing_rotation( + #XSDataBoolean(self.params_dict["reversing_rotation"]) + #) + ##TODO: the pixel sizes are 0?? + #pixel_size = HWR.beamline.detector.get_pixel_size() + #input_file.setPixelMin(XSDataInteger(pixel_size[0])) + #input_file.setPixelMax(XSDataInteger(pixel_size[1])) + ##input_file.setPixelMin(XSDataInteger(HWR.beamline.detector.get_pixel_min())) + ##input_file.setPixelMax(XSDataInteger(HWR.beamline.detector.get_pixel_max())) + ##input_file.setBeamstopSize(XSDataDouble(self.beamstop_hwobj.get_size())) + ##input_file.setBeamstopDistance(XSDataDouble(self.beamstop_hwobj.get_distance())) + ##input_file.setBeamstopDirection(XSDataString(self.beamstop_hwobj.get_direction())) + #input_file.setBeamstopSize( XSDataDouble(1.5) ) + #input_file.setBeamstopDistance( XSDataDouble(34) ) + #input_file.setBeamstopDirection( XSDataString("Y") ) + + input_file.exportToFile(processing_input_filename) + + def get_input_filename(self, data_collection): + # Create dozor dir as in XalocCollect + dozor_dir = self._create_proc_files_directory('dozor') + input_filename = os.path.join(dozor_dir, "dozor_input.xml") + return input_filename + + def stop_processing(self): + """Stops processing""" + self.started = False + self.set_processing_status("Stopped") + try: + self.pop_object.terminate() + except Exception as e: + self.logger.error("Cant stop processing: error is \n%s", e) + + + #def batch_processed2(self, batch): + #"""Method called from EDNA via xmlrpc to set results + + #:param batch: list of dictionaries describing processing results + #:type batch: lis + #""" + ## FORCED FOR TESTING + ##No longer self.started = True + + #self.logger.debug("Batch arrived %s" % str(self.started)) + #self.logger.debug("Batch is %s" % batch) + #if self.started and (type(batch) in (tuple, list)): + #if type(batch[0]) not in (tuple, list): + #batch = [batch] + #self.logger.debug("Batch, for each image in batch") + #for image in batch: + #frame_num = int(image[0]) + #self.logger.debug("Frame number is %s" % frame_num) + #self.results_raw["spots_num"][frame_num] = image[1] + #self.results_raw["spots_resolution"][frame_num] = 1 / image[3] + #self.results_raw["score"][frame_num] = image[2] + + #for score_key in self.results_raw.keys(): + #if self.params_dict["lines_num"] > 1: + #col, row = self.grid.get_col_row_from_image(frame_num) + #self.results_aligned[score_key][col][row] =\ + #self.results_raw[score_key][frame_num] + #else: + #self.results_aligned[score_key][frame_num] =\ + #self.results_raw[score_key][frame_num] + ## if self.params_dict["lines_num"] <= 1: + ## self.smooth() + + ## self.emit("paralleProcessingResults", + ## (self.results_aligned, + ## self.params_dict, + ## False)) + + def batch_processed(self, batch): + """Method called from EDNA via xmlrpc to set results + :param batch: list of dictionaries describing processing results + :type batch: lis + Reimplmented here for extra logging + """ + + #self.logger.debug("batch_processed called, batch is %s" % batch) + #self.logger.debug("Has process started? %s" % str(self.started)) + + if self.started: + for image in batch: + #self.logger.debug("Loop for each image in batch arrived") + #self.logger.debug("image is : %s" % image) + self.results_raw["spots_num"][image[0] - 1] = image[1] + self.results_raw["spots_resolution"][image[0] - 1] = image[3] + self.results_raw["score"][image[0] - 1] = image[2] + + self.align_processing_results(batch[0][0] - 1, batch[-1][0] - 1) + + #self.logger.debug("Emitting signal processingResultsUpdate") + + self.emit("processingResultsUpdate", False) + + # ONLY FOR ALBA!!! Similar function present in the XalocCollect + def _create_proc_files_directory(self, proc_name): + + path_template = self.data_collection.acquisitions[ + 0].path_template + proc_dir = path_template.process_directory + run_number = path_template.run_number + prefix = path_template.get_prefix() + + i = 1 + + while True: + logging.getLogger('HWR').debug('*** iteration %s' % i) + _dirname = "%s_%s_%s_%d" % ( + proc_name, + prefix, + run_number, + i) + _directory = os.path.join( + proc_dir, + _dirname) + if not os.path.exists(_directory): + break + i += 1 + + try: + logging.getLogger('HWR').debug( + 'Creating proc directory %s: ' % _directory) + self._create_directories(_directory) + os.system("chmod -R 777 %s" % _directory) + except Exception as e: + msg = "Could not create directory %s\n%s" % (_directory, str(e)) + logging.getLogger('HWR').exception(msg) + return + + # This is not yet implemented fpor dozor...maybe is not necesary + + # save directory names in current_dc_parameters. They will later be used + # by autoprocessing. + # key = "%s_dir" % proc_name + # self.current_dc_parameters[key] = _directory + # logging.getLogger('HWR').debug("dc_pars[%s] = %s" % (key, _directory)) + return _directory + + # The following methods are copied to improve error logging, the functionality is the same + def _create_directories(self, *args): + """ + Descript. : + """ + for directory in args: + logging.getLogger('HWR').debug('Creating directory %s: ' % directory) + try: + os.makedirs(directory) + except OSError as e: + import errno + if e.errno != errno.EEXIST: + logging.getLogger('HWR').error( + 'Error in making parallel processing directories') + raise + + def align_processing_results(self, start_index, end_index): + """Realigns all results. Each results (one dimensional numpy array) + is converted to 2d numpy array according to diffractometer geometry. + Function also extracts 10 (if they exist) best positions + """ + # Each result array is realigned + + self.logger.debug("align_processing_results, start_index %d, end_index %s, self.grid %s" % + (start_index, end_index, self.grid)) + for score_key in self.results_raw.keys(): + if ( + self.grid + #and self.results_raw[score_key].size == self.params_dict["images_num"] + ): + for cell_index in range(start_index, end_index + 1): + col, row = self.grid.get_col_row_from_image_serial( + cell_index + self.params_dict["first_image_num"] + ) + if ( + col < self.results_aligned[score_key].shape[0] + and row < self.results_aligned[score_key].shape[1] + ): + # to test the xray centering without beam, until "End of lines for test ----- + if self.testing: + self.results_raw[ score_key ][ cell_index ] = \ + pow( self.results_aligned[score_key].shape[0]/2., 2.001) + \ + pow( self.results_aligned[score_key].shape[1]/2. , 2.001) - \ + pow( -2. + col - self.results_aligned[score_key].shape[0]/2., 2.) - \ + pow( -1. + row - self.results_aligned[score_key].shape[1]/2., 2.) # to test the xray centering without beam + if self.results_raw[ score_key ][ cell_index ] < 0 : self.results_raw[ score_key ][ cell_index ] = 0 + # End of lines for test ---------------------------------------- + else: + self.results_aligned[score_key][col][row] = \ + self.results_raw[ score_key ][ cell_index ] + else: + self.results_aligned[score_key] = self.results_raw[score_key] + if self.interpolate_results: + x_array = numpy.linspace( + 0, + self.params_dict["images_num"], + self.params_dict["images_num"], + dtype=int, + ) + spline = UnivariateSpline( + x_array, self.results_aligned[score_key], s=10 + ) + self.results_aligned["interp_" + score_key] = spline(x_array) + + #self.logger.debug("self.results_aligned %s" % (str(self.results_aligned)) ) + + if self.grid: + # TODO: this should depend on the user selection of the self._score_type_cbox selection in the brick + self.grid.set_score(self.results_raw["score"]) + (center_x, center_y) = ndimage.measurements.center_of_mass( + self.results_aligned["score"] + ) + self.results_aligned["center_mass"] = self.grid.get_motor_pos_from_col_row( + center_x, center_y + ) + else: + centred_positions = self.data_collection.get_centred_positions() + if len(centred_positions) == 2: + center_x = ndimage.measurements.center_of_mass( + self.results_aligned["score"] + )[0] + self.results_aligned[ + "center_mass" + ] = HWR.beamline.diffractometer.get_point_from_line( + centred_positions[0], + centred_positions[1], + center_x, + self.params_dict["images_num"], + ) + else: + self.results_aligned["center_mass"] = centred_positions[0] + + #self.logger.debug("self.results_aligned %s" % (str(self.results_aligned)) ) + + # Best positions are extracted + best_positions_list = [] + + index_arr = (-self.results_raw["score"]).argsort()[:10] + if len(index_arr) > 0: + for index in index_arr: + if self.results_raw["score"][index] > 0: + best_position = {} + best_position["index"] = index + best_position["index_serial"] = ( + self.params_dict["first_image_num"] + index + ) + best_position["score"] = self.results_raw["score"][index] + best_position["spots_num"] = self.results_raw["spots_num"][index] + best_position["spots_resolution"] = self.results_raw[ + "spots_resolution" + ][index] + best_position["filename"] = os.path.basename( + self.params_dict["template"] + % ( + self.params_dict["run_number"], + self.params_dict["first_image_num"] + index, + ) + ) + + cpos = None + if self.grid: + col, row = self.grid.get_col_row_from_image_serial( + index + self.params_dict["first_image_num"] + ) + col += 0.5 + row = self.params_dict["steps_y"] - row - 0.5 + cpos = self.grid.get_motor_pos_from_col_row(col, row) + else: + col = index + row = 0 + cpos = None + # TODO make this nicer + # num_images = self.data_collection.acquisitions[0].acquisition_parameters.num_images - 1 + # (point_one, point_two) = self.data_collection.get_centred_positions() + # cpos = HWR.beamline.diffractometer.get_point_from_line(point_one, point_two, index, num_images) + best_position["col"] = col + best_position["row"] = row + best_position["cpos"] = cpos + best_positions_list.append(best_position) + + self.results_aligned["best_positions"] = best_positions_list + + self.logger.debug("after best_poitions: self.results_aligned %s" % (str(self.results_aligned)) ) + + def store_processing_results(self, status): + """ + Reimplement generation of json file that will fit XALOC preferences + + Note: the location of this file is sent ISpyB in the ISPyBClient module, in the store_workflow methods + """ + AbstractOnlineProcessing.store_processing_results(self, status) + # At this point, a html and json file have already been generated. We just want to overwrite the json file + try: + self.generate_online_processing_json_xaloc() + except Exception as e: + self.logger.error( + "Can not generate json file, error is %s" % ( str(e) ) + ) + self.logger.debug( "traceback %s" % traceback.format_exc() ) + + + def generate_online_processing_json_xaloc(self): + import json + from mxcubecore.HardwareObjects.SimpleHTML import create_json_images + + mesh_scan_results = self.results_aligned + params_dict = self.params_dict + json_dict = {"items": []} + + osc_range_per_line = params_dict["osc_range"] * (params_dict["images_per_line"] - 1) + + if params_dict["lines_num"] > 1: + json_dict["items"].append({"type": "title", "value": "Mesh scan results"}) + else: + json_dict["items"].append({"type": "title", "value": "Line scan results"}) + + # Add the table with the grid size + table_grid_size = { + "type":"table", + "title": "Grid size", + "orientation": "horizontal" + } + image = {"title": "plot", "filename": params_dict["cartography_path"]} + json_dict["items"].append(create_json_images([image])) + + if params_dict["lines_num"] > 1: + table_grid_size["columns"] = [ + "Grid size", + "Scan area", + "Horizontal distance between frames", + "Vertical distance between frames", + "Oscillation middle", + "Oscillation range per frame", + "Oscillation range per line", + ] + elif params_dict["lines_num"] == 1: + table_grid_size["columns"] = [ + "Grid size", + "Scan area", + "Horizontal distance between frames", + "Oscillation middle", + "Oscillation range per frame", + "Oscillation range per line", + ] + + data_array = [ + "%d x %d microns" + % ( + (params_dict["steps_x"] * params_dict["xOffset"] * 1000), + (params_dict["steps_y"] * params_dict["yOffset"] * 1000), + ), + "%d x %d microns" + % ((params_dict["dx_mm"] * 1000), (params_dict["dy_mm"] * 1000)), + "%d microns" % (params_dict["xOffset"] * 1000), + ] + if params_dict["lines_num"] > 1: + data_array.append( + "%d microns" % (params_dict["yOffset"] * 1000), + ) + data_array.extend( [ + "%.1f" % params_dict["osc_midle"], + "%.2f" % params_dict["osc_range"], + "%.2f (from %.2f to %2.f)" + % ( + osc_range_per_line, + (params_dict["osc_midle"] - osc_range_per_line / 2), + (params_dict["osc_midle"] + osc_range_per_line / 2), + ), + ]) + table_grid_size["data"] = [data_array] + json_dict["items"].append(table_grid_size) + + # Add the table with the best positions + table_best_positions= {} + positions = mesh_scan_results.get("best_positions", []) + if len(positions) > 0: + data_array = [[]] + # TODO convert following two lines to json equivalent + #html_file.write(create_text("All positions", heading=1)) + #html_file.write("
") + + table_best_positions = { + "type":"table", + "title": "Grid size", + "columns": [ + "Index", + "Score", + "Number of spots", + "Resolution", + "File name", + "Column", + "Row" + ], + "orientation": "horizontal" + } + pos = 0 + for position in positions: + data_array[pos] = \ + [ + "%d" % position["index"], + "%.2f" % position["score"], + "%d" % position["spots_num"], + "%.1f" % position["spots_resolution"], + position["filename"], + "%d" % (position["col"] + 1), + "%d" % (position["row"] + 1), + ] + pos+=1 + table_best_positions["data"] = data_array + json_dict["items"].append(table_best_positions) + + self.logger.debug("writing json file %s" % (params_dict["json_file_path"]) ) + open(params_dict["json_file_path"], "w").write(json.dumps(json_dict, indent=4)) + + # def update_map(self): + # """Updates plot map + # + # :return: None + # """ + # gevent.sleep(1) + # while self.started: + # self.emit("paralleProcessingResults", + # (self.results_aligned, + # self.params_dict, + # False)) + # if self.params_dict["lines_num"] > 1: + # self.grid.set_score(self.results_raw['score']) + # gevent.sleep(0.5) + # + # def set_processing_status(self, status): + # """Sets processing status and finalize the processing + # Method called from EDNA via xmlrpc + # + # :param status: processing status (Success, Failed) + # :type status: str + # """ + # self.batch_processed(self.chan_dozor_pass.get_value()) + # GenericParallelProcessing.set_processing_status(self, status) + # + # def store_processing_results(self, status): + # GenericParallelProcessing.store_processing_results(self, status) + # self.display_task.kill() + # + # processing_xml_filename = os.path.join(self.params_dict\ + # ["directory"], "dozor_result.xml") + # dozor_result = XSDataResultControlDozor() + # for index in range(self.params_dict["images_num"]): + # dozor_image = XSDataControlImageDozor() + # dozor_image.setNumber(XSDataInteger(index)) + # dozor_image.setScore(XSDataDouble(self.results_raw["score"][index])) + # dozor_image.setSpots_num_of(XSDataInteger(self.results_raw["spots_num"][index])) + # dozor_image.setSpots_resolution(XSDataDouble(self.results_raw["spots_resolution"][index])) + # dozor_result.addImageDozor(dozor_image) + # dozor_result.exportToFile(processing_xml_filename) + # logging.getLogger("HWR").info("Parallel processing: Results saved in %s" % processing_xml_filename) + + def is_running(self): + """Returns True if processing is running""" + return self.started + diff --git a/mxcubecore/HardwareObjects/ALBA/XalocPilatus.py b/mxcubecore/HardwareObjects/ALBA/XalocPilatus.py new file mode 100755 index 0000000000..939e72a729 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocPilatus.py @@ -0,0 +1,557 @@ +# +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] +XalocPilatus + +[Description] +Specific HwObj to interface the Pilatus2 6M detector + +[Emitted signals] +- None +""" + +from __future__ import print_function + +import logging +import time + +from datetime import datetime +from mxcubecore.HardwareObjects.abstract.AbstractDetector import ( + AbstractDetector, +) +#from mxcubecore.BaseHardwareObjects import HardwareObject +from taurus import Device +from mxcubecore import HardwareRepository as HWR + +__credits__ = ["ALBA"] +__version__ = "3." +__category__ = "General" + + +ENERGY_CHANGE_LIMIT=1.2 + + +class XalocPilatus(AbstractDetector): + """Detector class. Contains all information about detector + - states are 'OK', and 'BAD' + - status is busy, exposing, ready, etc. + - physical property is RH for pilatus, P for rayonix + """ + + def __init__(self, name): + AbstractDetector.__init__(self, name) + #HardwareObject.__init__(self, name) + self.logger = logging.getLogger("HWR.XalocPilatus") + self.cmd_prepare_acq = None + self.cmd_start_acq = None + self.cmd_abort_acq = None + self.cmd_stop_acq = None + self.cmd_reset_common_header = None + self.cmd_reset_frame_headers = None + self.cmd_set_image_header = None + + #self.cmd_set_threshold_gain = None + + self.chan_saving_mode = None + self.chan_saving_prefix = None + self.chan_saving_directory = None + self.chan_saving_format = None + self.chan_saving_next_number = None + self.chan_saving_header_delimiter = None + self.chan_saving_statistics = None + + self.chan_acq_nb_frames = None + self.chan_acq_trigger_mode = None + self.chan_acq_expo_time = None + self.chan_acq_status = None + self.chan_acq_status_fault_error = None + self.chan_lima_ready = None + + self.latency_time = None + self.chan_latency_time = None + + self.chan_energy = None + self.chan_threshold = None + #self.chan_gain = None + self.chan_cam_state = None + self.cmd_cam_server = None + + self.chan_beam_x = None + self.chan_beam_y = None + self.chan_eugap = None + + self.default_distance = None + self.default_distance_limits = None + self.exp_time_limits = None + self.device = None + self.start_acq_cam_server = None + + self.headers = {} + + def init(self): + AbstractDetector.init(self) + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + + self.latency_time = self.get_property("latency_time") + + self.cmd_prepare_acq = self.get_command_object('prepare_acq') + self.cmd_start_acq = self.get_command_object('start_acq') + self.cmd_abort_acq = self.get_command_object('abort_acq') + self.cmd_stop_acq = self.get_command_object('stop_acq') + self.cmd_reset = self.get_command_object('reset') + self.cmd_reset_common_header = self.get_command_object('reset_common_header') + self.cmd_reset_frame_headers = self.get_command_object('reset_frame_headers') + self.cmd_set_image_header = self.get_command_object('set_image_header') + + #self.cmd_set_threshold_gain = self.get_command_object('set_threshold_gain') + + self.chan_saving_mode = self.get_channel_object('saving_mode') + self.chan_saving_prefix = self.get_channel_object('saving_prefix') + self.chan_saving_directory = self.get_channel_object('saving_directory') + self.chan_saving_format = self.get_channel_object('saving_format') + self.chan_saving_next_number = self.get_channel_object('saving_next_number') + self.chan_saving_header_delimiter = self.get_channel_object( + 'saving_header_delimiter') + self.chan_saving_statistics = self.get_channel_object('saving_statistics') + + self.chan_acq_nb_frames = self.get_channel_object('acq_nb_frames') + self.chan_acq_trigger_mode = self.get_channel_object('acq_trigger_mode') + self.chan_acq_expo_time = self.get_channel_object('acq_expo_time') + self.chan_acq_status = self.get_channel_object('acq_status') + self.chan_acq_status_fault_error = self.get_channel_object( + 'acq_status_fault_error') + self.chan_lima_ready = self.get_channel_object('lima_ready_for_next_acq') + self.chan_latency_time = self.get_channel_object('latency_time') + + if self.latency_time == None: + self.latency_time = self.chan_latency_time.get_value() + else: + self.chan_latency_time.set_value( self.latency_time ) + + self.chan_energy = self.get_channel_object('energy') + self.chan_threshold = self.get_channel_object('threshold') + #self.chan_gain = self.get_channel_object('gain') + self.chan_cam_state = self.get_channel_object('cam_state') + self.cmd_cam_server = self.get_command_object('cmd_cam_server') + + # TODO: set timeout via xml but for command? + name = self.get_property("taurusname") + self.device = Device(name) + self.device.set_timeout_millis(30000) + + exp_time_limits = self.get_property("exposure_limits") + self.exp_time_limits = map(float, exp_time_limits.strip().split(",")) + self.start_acq_cam_server = self.get_property("start_acq_cam_server") + + self.chan_beam_x = self.get_channel_object("beamx") + self.chan_beam_y = self.get_channel_object("beamy") + self.chan_eugap = self.get_channel_object("eugap") + + def start_acquisition(self): + if self.start_acq_cam_server is True: + #TODO format the number of digits correctly + first_file_name = self.chan_saving_prefix.get_value() + \ + "%04d" % self.chan_saving_next_number.get_value() + \ + "." + self.chan_saving_format.get_value().lower() + self.cmd_cam_server("ExtTrigger %s" % first_file_name) + else: + self.cmd_start_acq() + + def stop_acquisition(self): + self.logger.debug("Stopping detector and resetting it") + if self.start_acq_cam_server is True: + self.cmd_cam_server("k") + self.wait_not_running() + self.chan_energy.set_value( self._get_beamline_energy() ) + else: + #self.cmd_stop_acq() + self.cmd_abort_acq() + self.wait_not_running() + time.sleep(0.1) + self.cmd_reset() + + def get_radius(self, distance=None): + """Get distance from the beam position to the nearest detector edge. + Args: + distance (float): Distance [mm] + Returns: + (float): Detector radius [mm] + """ + try: + distance = distance or self._distance_motor_hwobj.get_value() + except AttributeError: + raise RuntimeError("Cannot calculate radius, distance unknown") + + beam_x, beam_y = self.get_beam_position(distance) + pixel_x, pixel_y = self.get_pixel_size() + rrx = min(self.get_width() - beam_x, beam_x) * pixel_x + rry = min(self.get_height() - beam_y, beam_y) * pixel_y + radius = min(rrx, rry) + + return radius + + + def get_distance(self): + """Returns detector distance in mm""" + if self._distance_motor_hwobj is not None: + return float( self._distance_motor_hwobj.get_value() ) + else: + return self.default_distance + + def move_distance(self, value): + if self._distance_motor_hwobj is not None: + self._distance_motor_hwobj.move(value) + + def wait_move_distance_done(self): + self._distance_motor_hwobj.wait_ready(1000) + #self._distance_motor_hwobj.wait_end_of_move(timeout=1000) # wait_end_of_nove does not work! + + def wait_ready(self): + self.wait_move_distance_done() + self.wait_standby() + + def wait_lima_ready(self): + self.wait_move_distance_done() + self.wait_lima_ready_for_next_acq() + + def get_distance_limits(self): + """Returns detector distance limits""" + if self._distance_motor_hwobj is not None: + return self._distance_motor_hwobj.get_limits() + else: + return self.default_distance_limits + + def get_energy(self): + return self.chan_energy.get_value() + + def get_threshold(self): + return self.chan_threshold.get_value() + + #def get_gain(self): + #return self.chan_gain.get_value() + + def get_cam_state(self): + return self.chan_cam_state.force_get_value() + + def has_shutterless(self): + """Return True if has shutterless mode""" + return True + + def get_beam_position(self, distance=None, wavelength=None): + """ + Returns beam center coordinates + TODO: update values according to distance, see XALOC modules for the calculation and calibration + """ + beam_x = 0 + beam_y = 0 + try: + beam_x = self.chan_beam_x.get_value() + beam_y = self.chan_beam_y.get_value() + except BaseException as e: + self.logger.debug("Cannot load beam channels\n%s" % str(e)) + return beam_x, beam_y + + def get_manufacturer(self): + return self.get_property("manufacturer") + + def get_model(self): + return self.get_property("model") + + def get_detector_type(self): + return self.get_property("type") + + def get_default_exposure_time(self): + return self.get_property("default_exposure_time") + + def get_minimum_exposure_time(self): + return self.get_property("minimum_exposure_time") + + def get_exposure_time_limits(self): + """Returns exposure time limits as list with two floats""" + return self.exp_time_limits + + def get_file_suffix(self): + return self.get_property("file_suffix") + + def get_pixel_size(self): + return self.get_property("px"), self.get_property("py") + + def _get_beamline_energy(self): + try: + beamline_energy = self.chan_eugap.get_value() + except Exception as e: + self.logger.debug("Error getting energy\n%s" % str(e)) + beamline_energy = 12.6 + self.logger.debug("Setting default energy = %s" % beamline_energy) + return beamline_energy + + #def set_gain(self, value): + #self.chan_gain.set_value(value) + + def arm(self): + """ + Configure detector electronics. + :return: + """ + self.logger.debug("Arming the detector") + try: + beamline_energy = self._get_beamline_energy() + energy = self.get_energy() + threshold = self.get_threshold() + #threshold_gain = self.get_gain() + cam_state = self.get_cam_state() + + self.logger.debug("beamline energy (Eb): %s" % beamline_energy) + self.logger.debug("energy_threshold (Eth): %s" % energy) + #self.logger.debug("current threshold gain: %s" % threshold_gain) + + if abs(energy - beamline_energy) > ENERGY_CHANGE_LIMIT: + self.chan_energy.set_value(beamline_energy) + logging.getLogger("user_level_log").info( + "Setting detector energy_threshold: %s" % beamline_energy) + # wait until detector is configured + # Wait for 3 secs to let time for iState to change + time.sleep(3) + if not self.wait_standby(): + raise RuntimeError("Detector could not be configured!") + else: + logging.getLogger("user_level_log").info("Energy difference (Eth - Eb) is below the difference limit %s keV" % ENERGY_CHANGE_LIMIT) + logging.getLogger("user_level_log").info("Detector energy threshold will remain unchanged (%s keV)" % energy) + +# if round(beamline_energy, 6) < 7.538: +# beamline_energy = 7.538 +# +# kev_diff = abs(energy - beamline_energy) +# +# if kev_diff > 1.2 or beamline_energy > 10.0: +# if cam_state == 'STANDBY': +# if beamline_energy > 10.0: +# if threshold_gain != 'LOW': +# self.set_threshold_gain('LOW') +# self.logger.debug( +# "Setting threshold_gain to LOW for energy %s > 10keV" % str(round(kev_diff, 4))) +# else: +# self.chan_energy_threshold = beamline_energy +# self.logger.debug( +# "Setting detector energy_threshold: %s" % beamline_energy) +# # wait until detector is configured +# # Wait for 3 secs to let time for change +# time.sleep(3) +# if not self.wait_standby(): +# raise RuntimeError("Detector could not be configured!") +# else: +# msg = "Cannot set energy threshold, detector not in STANDBY" +# raise RuntimeError(msg) + except Exception as e: + self.logger.error("Exception when setting threshold to pilatus: %s" % str(e)) + + def get_latency_time(self): + if self.latency_time != None: + return self.latency_time + return self.chan_latency_time.get_value() + + def wait_standby(self, timestep = 0.1, timeout=300): + standby = self.get_cam_state() + if standby != 'STANDBY': + self.logger.debug("Waiting detector to be in STANDBY") + t0 = time.time() + while standby != 'STANDBY' and standby != 'ERROR': + if time.time() - t0 > timeout: + self.logger.debug("timeout waiting for Pilatus to be on STANDBY") + return False + time.sleep(timestep) + standby = self.get_cam_state() + #self.logger.debug("Detector is %s" % self.get_cam_state()) + if standby == 'STANDBY': return True + return False + + def wait_lima_ready_for_next_acq(self, timeout=300): + lima_ready = self.chan_lima_ready.get_value() + if lima_ready != True: + logging.getLogger("").info("Waiting detector lima to be ready for next image") + t0 = time.time() + while lima_ready != True and HWR.beamline.collect._collecting and self.get_cam_state() != 'ERROR': + if time.time() - t0 > timeout: + self.logger.debug("timeout waiting for Pilatus lima to be ready for next image") + return False + time.sleep(0.1) + lima_ready = self.chan_lima_ready.get_value() + #self.logger.debug("Detector lima ready for next image is %s" % lima_ready ) + return True + + def wait_running(self, timestep=0.1, timeout=300): + self.logger.debug("Waiting detector to be in RUNNING") + t0 = time.time() + while self.get_cam_state() != 'RUNNING': + if time.time() - t0 > timeout: + self.logger.debug("timeout waiting for Pilatus to be inn RUNNING state") + return False + time.sleep( timestep ) + #self.logger.debug("Detector is %s" % self.get_cam_state()) + return True + + def wait_not_running(self, timestep=0.1, timeout=300): + self.logger.debug("Waiting detector to stop RUNNING") + t0 = time.time() + self.logger.debug("wait_not_running: Detector is %s" % self.get_cam_state()) + while self.get_cam_state() == 'RUNNING': + if time.time() - t0 > timeout: + self.logger.debug("timeout waiting for Pilatus to stop RUNNING") + return False + time.sleep( timestep ) + #self.logger.debug("Detector is %s" % self.get_cam_state()) + return True + + def prepare_acquisition(self, dcpars): + + self.arm() + latency_time = self.get_latency_time() + + osc_seq = dcpars['oscillation_sequence'][0] + file_pars = dcpars['fileinfo'] + + basedir = file_pars['directory'] + prefix = "%s_%s_" % (file_pars['prefix'], file_pars['run_number']) + + #TODO: deprecated + # first_img_no = osc_seq['start_image_number'] + nb_frames = osc_seq['number_of_images'] + exp_time = osc_seq['exposure_time'] + + fileformat = "CBF" + trig_mode = dcpars['detector_binning_mode'][0] + + self.logger.debug(" Preparing detector for data collection") + + self.logger.debug(" /saving directory: %s" % basedir) + self.logger.debug(" /prefix : %s" % prefix) + self.logger.debug(" /saving_format : %s" % fileformat) + self.logger.debug(" /trigger_mode : %s" % trig_mode) + self.logger.debug(" /acq_nb_frames : %s" % nb_frames) + self.logger.debug(" /acq_expo_time : %s" % + str(exp_time - latency_time)) + self.logger.debug(" /latency_time : %s" % latency_time) + + self.chan_saving_mode.set_value('AUTO_FRAME') + self.chan_saving_directory.set_value(basedir) + self.chan_saving_prefix.set_value(prefix) + self.chan_saving_format.set_value(fileformat) + + self.chan_acq_trigger_mode.set_value(trig_mode) + + return True + + def set_exposure_time(exp_period): + self.chan_acq_expo_time.set_value(exp_period - latency_time) + + def prepare_collection(self, nb_frames, first_img_no, exp_time): + self.logger.debug("Preparing collection") + self.logger.debug("# images = %s, first image number: %s, exp_time %.4f" % + (nb_frames, first_img_no, exp_time) + ) + self.chan_acq_nb_frames.set_value(nb_frames) + self.chan_saving_next_number.set_value(first_img_no) + self.chan_acq_expo_time.set_value(exp_time) + self.cmd_prepare_acq() + return True + + def start_collection(self): + self.start_acquisition() + + def stop_collection(self): + self.stop_acquisition() + + def set_image_headers(self, image_headers, angle_info): + """ + Prepares headers both in lima as well as the camserver + TODO: use start_acq_cam_server to set the appropriate header + """ + + nb_images = image_headers['nb_images'] + angle_inc = image_headers['Angle_increment'] + start_angle = image_headers['Start_angle'] + + ang_start, ang_inc, spacing = angle_info + + #Set the camserver headings in case lima is not used + self.cmd_cam_server("MXsettings Start_angle %s" % image_headers["Start_angle"].split()[0] ) + self.cmd_cam_server("MXsettings Angle_increment %s" % image_headers["Angle_increment"].split()[0] ) + self.cmd_cam_server("MXsettings Kappa %s" % image_headers["Kappa"].split()[0] ) + self.cmd_cam_server("MXsettings Phi %s" % image_headers["Phi"].split()[0] ) + self.cmd_cam_server("MXsettings Flux %s" % image_headers["Flux"].split()[0] ) + self.cmd_cam_server("MXsettings Wavelength %s" % image_headers["Wavelength"].split()[0] ) + self.cmd_cam_server("MXsettings Filter_transmission %s" % image_headers["Filter_transmission"].split()[0] ) + self.cmd_cam_server("MXsettings Detector_distance %s" % image_headers["Detector_distance"].split()[0] ) + self.cmd_cam_server("MXsettings Polarization %s" % image_headers["Polarization"].split()[0] ) + self.cmd_cam_server("MXsettings Detector_2theta %s" % image_headers["Detector_2theta"].split()[0] ) + self.cmd_cam_server("MXsettings Beam_xy %s" % image_headers["Beam_xy"].split("pixels")[0] ) + self.cmd_cam_server("MXsettings Detector_Voffset %s" % image_headers["Detector_Voffset"].split()[0] ) + self.cmd_cam_server("MXsettings Oscillation_axis %s" % image_headers["Oscillation_axis"] ) + + startangles_list = list() + for i in range(nb_images): + startangles_list.append("%0.4f deg." % (ang_start + spacing * i)) + + headers = list() + for i, sa in enumerate(startangles_list): + header = "# Detector: PILATUS3X 6M, S/N 60-0140, XALOC, Alba\n" \ + "# %s\n" \ + "# Pixel_size 172e-6 m x 172e-6 m\n" \ + "# Silicon sensor, thickness 0.001 m\n" % datetime.now().strftime( + "%Y-%m-%dT%T.%f")[:-3] + + # Acquisition values (headers dictionary) but overwrites start angle + image_headers["Start_angle"] = sa + for key, value in image_headers.iteritems(): + if key == 'nb_images': + continue + header += "# %s %s\n" % (key, value) + headers.append("%d : array_data/header_convention|%s;" % (i, "PILATUS_1.2")) + headers.append("%d : array_data/header_contents|%s;" % (i, header)) + + #self.logger.debug(" saving header delimiters %s" % ["|", ";", ":"]) + self.chan_saving_header_delimiter.set_value(["|", ";", ":"]) + #self.logger.debug(" reset_common_header" ) + self.cmd_reset_common_header() + #self.logger.debug(" reset_frame_headers" ) + self.cmd_reset_frame_headers() + #self.logger.debug(" set_image_header %s" % headers) + self.cmd_set_image_header(headers) + + def get_saving_statistics(self): + values = self.chan_saving_statistics.get_value() + if all(values): + saving_speed, compression_speed, compression_ratio, incoming_speed = values + comp_ratio = compression_speed / incoming_speed + saving_ratio = saving_speed / (incoming_speed / compression_ratio) + + self.logger.debug(" compression ratio = %.4f" % comp_ratio) + self.logger.debug(" saving ratio = %.4f" % saving_ratio) + self.logger.debug("If comp_ratio < 1, increase the NbProcessingThread") + self.logger.debug( + "If saving_ratio < 1, increase the SavingMaxConcurrentWritingTask") + else: + self.logger.debug("No data available to evaluate the Pilatus/Lima performance") + self.logger.debug("raw values --> %s" % values) + +def test_hwo(hwo): + for chan in hwo.getChannels(): + print("%s = %s" % (chan.userName(), chan.get_value())) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocQtGraphicsManager.py b/mxcubecore/HardwareObjects/ALBA/XalocQtGraphicsManager.py new file mode 100644 index 0000000000..685e61a179 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocQtGraphicsManager.py @@ -0,0 +1,225 @@ +# 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 . + +""" +Qt4/5/PySide Graphics manager for MxCuBE. +Hardware object handles QGraphicsView and QGraphicsScene with all +objects and actions necessary for MXCuBE: +- Creating/removing/editing/drawing of centring points, collection vectors + and 2D grids +- Display of beam shape, rotatio axis, scales +- Distance, angle and area measurement tools +- Video handling, scalling and magnification tools + +example xml: + + + + + + {"scale": 4, "area_size": 50} + +""" + +import logging + +from mxcubecore.HardwareObjects.QtGraphicsManager import QtGraphicsManager +from mxcubecore.HardwareObjects import QtGraphicsLib as GraphicsLib +from mxcubecore import HardwareRepository as HWR + +class XalocQtGraphicsManager(QtGraphicsManager): + def __init__(self, name): + QtGraphicsManager.__init__(self, name) + self.userlogger = logging.getLogger("user_level_log") + + def mouse_clicked(self, pos_x, pos_y, left_click=True): + """Method when mouse clicked on GraphicsScene + + :param pos_x: screen coordinate X + :type pos_x: int + :param pos_y: screen coordinate Y + :type pos_y: int + :param left_click: left button clicked + :type left_click: bool + :emits: - shapeSelected + - pointSelected + - infoMsg + """ + if self.in_centring_state: + if self.current_centring_method == HWR.beamline.diffractometer.CENTRING_METHOD_MANUAL: + self.graphics_centring_lines_item.add_position(pos_x, pos_y) + self.diffractometer_hwobj.image_clicked(pos_x, pos_y) + else: + self.userlogger.error("Click ignored, not in manual centring. ") + self.userlogger.error("\tChange centring procedure in the \"Centring\" pulldown close to the ISPyB button if necessary") + elif self.wait_grid_drawing_click: + self.in_grid_drawing_state = True + self.graphics_grid_draw_item.set_draw_mode(True) + self.graphics_grid_draw_item.set_start_position(pos_x, pos_y) + self.graphics_grid_draw_item.show() + elif self.wait_measure_distance_click: + self.start_graphics_item(self.graphics_measure_distance_item) + self.in_measure_distance_state = True + self.wait_measure_distance_click = False + elif self.wait_measure_angle_click: + self.start_graphics_item(self.graphics_measure_angle_item) + self.in_measure_angle_state = True + self.wait_measure_angle_click = False + elif self.wait_measure_area_click: + self.start_graphics_item(self.graphics_measure_area_item) + self.in_measure_area_state = True + self.wait_measure_area_click = False + elif self.wait_beam_define_click: + self.start_graphics_item(self.graphics_beam_define_item) + self.in_beam_define_state = True + self.wait_beam_define_click = False + elif self.in_measure_distance_state: + self.graphics_measure_distance_item.store_coord(pos_x, pos_y) + elif self.in_measure_angle_state: + self.graphics_measure_angle_item.store_coord(pos_x, pos_y) + elif self.in_measure_area_state: + self.graphics_measure_area_item.store_coord() + elif self.in_move_beam_mark_state: + self.stop_move_beam_mark() + elif self.in_beam_define_state: + self.stop_beam_define() + # self.graphics_beam_define_item.store_coord(pos_x, pos_y) + elif self.in_one_click_centering: + self.diffractometer_hwobj.start_move_to_beam(pos_x, pos_y) + else: + self.emit("pointSelected", None) + self.emit("infoMsg", "") + if left_click: + self.graphics_select_tool_item.set_start_position(pos_x, pos_y) + self.graphics_select_tool_item.set_end_position(pos_x, pos_y) + self.graphics_select_tool_item.show() + self.in_select_items_state = True + for graphics_item in self.graphics_view.scene().items(): + graphics_item.setSelected(False) + if type(graphics_item) in [ + GraphicsLib.GraphicsItemPoint, + GraphicsLib.GraphicsItemLine, + GraphicsLib.GraphicsItemGrid, + ]: + self.emit("shapeSelected", graphics_item, False) + # if isinstance(graphics_item, GraphicsLib.GraphicsItemPoint): + # self.emit("pointSelected", graphics_item) + + def mouse_double_clicked(self, pos_x, pos_y): + """If in one of the measuring states, then stops measuring. + Otherwise moves to screen coordinate + + :param pos_x: screen coordinate X + :type pos_x: int + :param pos_y: screen coordinate Y + :type pos_y: int + """ + if self.in_centring_state: + self.userlogger.error("Double click ignored, centring in progress. ") + self.userlogger.error("\tWait for the centring procedure to finish") + elif self.in_measure_distance_state: + self.stop_measure_distance() + elif self.in_measure_angle_state: + self.stop_measure_angle() + elif self.in_measure_area_state: + self.stop_measure_area() + elif self.in_beam_define_state: + self.stop_beam_define() + else: + self.diffractometer_hwobj.move_to_beam(pos_x, pos_y) + self.emit("imageDoubleClicked", pos_x, pos_y) + + def diffractometer_pixels_per_mm_changed(self, pixels_per_mm): + """Updates graphics scale when zoom changed + + :param pixels_per_mm: two floats for scaling + :type pixels_per_mm: list with two floats + """ + + if type(pixels_per_mm) in (list, tuple): + if pixels_per_mm != self.pixels_per_mm: + self.pixels_per_mm = pixels_per_mm + for item in self.graphics_view.graphics_scene.items(): + if isinstance(item, GraphicsLib.GraphicsItem): + item.set_pixels_per_mm(self.pixels_per_mm) + self.diffractometer_state_changed() + self.graphics_view.graphics_scene.update() + + + # CHECK: accept_centring, reject_centring, cancel_centring, start_one_click_centring, stop_one_click_centring + # did not have an emit, but this perhaps is done through emits from the diffractometer?? + def accept_centring(self): + """Accepts centring + """ + self.set_cursor_busy(False) + self.diffractometer_hwobj.accept_centring() + self.diffractometer_state_changed() + self.show_all_items() + self.emit("centringInProgress", False) + + def reject_centring(self): + """Rejects centring + """ + self.set_cursor_busy(False) + self.diffractometer_hwobj.reject_centring() + self.show_all_items() + self.emit("centringInProgress", False) + + def cancel_centring(self, reject=False): + """Cancels centring + + :param reject: reject position + :type reject: bool + """ + self.set_cursor_busy(False) + self.diffractometer_hwobj.cancel_centring_method(reject=reject) + self.show_all_items() + self.emit("centringInProgress", False) + + def start_one_click_centring(self): + self.set_cursor_busy(True) + self.emit("infoMsg", "Click on the screen to create centring points") + self.in_one_click_centering = True + self.graphics_centring_lines_item.setVisible(True) + self.emit("centringInProgress", True) + + def stop_one_click_centring(self): + self.set_cursor_busy(False) + self.emit("infoMsg", "") + self.in_one_click_centering = False + self.graphics_centring_lines_item.setVisible(False) + self.emit("centringInProgress", False) + + def create_grid(self, spacing=(0, 0)): + """Creates grid + + :param spacing: spacing between beams + :type spacing: list with two floats (can be negative) + """ + if not self.wait_grid_drawing_click: + self.set_cursor_busy(True) + self.graphics_grid_draw_item = GraphicsLib.GraphicsItemGrid( + self, self.beam_info_dict, spacing, self.pixels_per_mm + ) + self.graphics_grid_draw_item.set_draw_mode(True) + self.graphics_grid_draw_item.index = self.grid_count + self.grid_count += 1 + self.graphics_view.graphics_scene.addItem(self.graphics_grid_draw_item) + self.wait_grid_drawing_click = True + self.emit('gridDrawn') + diff --git a/mxcubecore/HardwareObjects/ALBA/XalocQtTangoLimaVideo.py b/mxcubecore/HardwareObjects/ALBA/XalocQtTangoLimaVideo.py new file mode 100755 index 0000000000..6debe83e98 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocQtTangoLimaVideo.py @@ -0,0 +1,162 @@ +# +# 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 . + +""" +[Name] +XalocQtTangoLimaVideo + +[Description] +HwObj used to grab images via Tango LImA library or Lima Tango server, based on QtTangoLimaVideo. + +[Configuration] +See example below. To select between "Library" or "Tango" simply +use and configure the field
(for Library) +or (for Tango) +in the XML file. + + +Example Hardware Object XML file : +================================== + + basler + yuv422p +
84.89.227.6
+ 0.5 + 0.01 + (False, False) + 30 +
+""" + +__credits__ = ["ALBA"] +__version__ = "3." +__category__ = "General" + +import sys +import numpy as np + +import logging + +from mxcubecore.HardwareObjects.QtTangoLimaVideo import QtTangoLimaVideo +from mxcubecore.HardwareObjects.abstract.AbstractVideoDevice import ( + AbstractVideoDevice, +) + +try: + import cv2 +except: + pass + +module_names = ["qt", "PyQt5", "PyQt4"] + +if any(mod in sys.modules for mod in module_names): + USEQT = True + try: + from PyQt5.QtGui import QImage, QPixmap + except ImportError: + from PyQt4.QtGui import QImage, QPixmap +else: + USEQT = False + from PIL import Image + +class XalocQtTangoLimaVideo(QtTangoLimaVideo): + """ + Descript. : + """ + + def __init__(self, name): + """ + Descript. : + """ + self.logger = logging.getLogger("HWR") + self.logger.debug("XalocQtTangoLimaVideo.__init__()") + QtTangoLimaVideo.__init__(self, name) + self.align_mode = None + + def init(self): + QtTangoLimaVideo.init(self) + # TODO: Sometimes, the error Can't set live mode if an acquisition is running appears. The bzoom DS needs to be restarted in that case + # check refresh_camera method of the camera / sample_view + self.align_mode = False + + def set_cam_encoding(self, cam_encoding): + self.logger.debug("XalocQtTangoLimaVideo set_cam_encoding") + if cam_encoding == "yuv422p": + self.device.video_mode = "YUV422" + if cam_encoding == "rgb24": + self.device.video_mode = "RGB24" + elif cam_encoding == "y8": + self.device.video_mode = "Y8" + elif cam_encoding.lower() == "bayer_rg16": + self.device.video_mode = "BAYER_RG16" + + self.logger.debug( + "%s: using %s encoding" % + (self.name, cam_encoding) + ) + + AbstractVideoDevice.set_cam_encoding(self, cam_encoding) + + self.logger.debug( + "%s: using %s encoding" % + (self.name, cam_encoding) + ) + + + def get_new_image(self): + """ + Descript. : + """ + raw_buffer, width, height = self.get_image() + + # self.cam_type is bzoom + + if raw_buffer is not None and raw_buffer.any(): + if self.cam_type == "basler": + raw_buffer = self.decoder(raw_buffer) + if self.align_mode: + raw_buffer = cv2.applyColorMap(raw_buffer, cv2.COLORMAP_JET) + + qimage = QImage(raw_buffer, width, height, + width * 3, + QImage.Format_RGB888) + else: + raw_buffer = self.bgr_2_rgb(raw_buffer) + if self.align_mode: + raw_buffer = cv2.applyColorMap(cv2.bitwise_not(raw_buffer), cv2.COLORMAP_JET) + + qimage = QImage(raw_buffer, width, height, + QImage.Format_RGB888) + + if self.cam_mirror is not None: + qimage = qimage.mirrored(self.cam_mirror[0], self.cam_mirror[1]) + + if self.scale != 1: + dims = self.get_image_dimensions() # should be already scaled + qimage = qimage.scaled(QSize(dims[0], dims[1])) + + qpixmap = QPixmap(qimage) + self.emit("imageReceived", qpixmap) + return qimage.copy() + + def bgr_2_rgb(self, raw_buffer): + image = np.fromstring(raw_buffer, dtype=np.uint8) + raw_dims = self.get_raw_image_size() + image.resize(raw_dims[1], raw_dims[0], 3) + return cv2.cvtColor(image, cv2.COLOR_BGR2RGB) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocResolution.py b/mxcubecore/HardwareObjects/ALBA/XalocResolution.py new file mode 100644 index 0000000000..51da0c81f1 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocResolution.py @@ -0,0 +1,103 @@ +from mxcubecore import HardwareRepository as HWR +from mxcubecore.HardwareObjects.Resolution import Resolution +import logging +import math + +from mxcubecore.HardwareObjects.abstract.AbstractMotor import ( + MotorStates, +) + +class XalocResolution(Resolution): + + unit = "A" + + #def __init__(self, *args, **kwargs): + def __init__(self, name): + #Resolution.__init__(self, name="XalocResolution") + super(XalocResolution, self).__init__(name) + self.logger = logging.getLogger("HWR.XalocResolution") + + #self._chnBeamX = None + #self._chnBeamY = None + self.resedge = None + + def init(self): + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + #super(XalocResolution, self).init() + + self._hwr_detector = ( + self.get_object_by_role("detector") or HWR.beamline.detector + ) + self.resedge = self.get_channel_object("resedge_value") + + self.connect(self.resedge, "valueChanged", self.set_value) + if HWR.beamline.energy is not None: + HWR.beamline.energy.connect("energyChanged", self.update_energy) + self.connect(self._hwr_detector.distance, "stateChanged", self.update_state) + self.connect(self._hwr_detector.distance, "valueChanged", self.update_distance) + + + def is_ready(self): + return self._hwr_detector.distance.get_state() == MotorStates.READY + + + #def get_beam_centre(self, dtox=None): + #return self._chnBeamX.get_value(), self._chnBeamY.get_value() + + #def get_value_at_corner(self): + #if self.rescorner is not None: + #return self.rescorner.get_value() + + def get_limits(self): + """Return resolution low and high limits. + Returns: + (tuple): two floats tuple (low limit, high limit). + """ + _low, _high = self._hwr_detector.distance.get_limits() + + self._limits = ( + self.distance_to_resolution(_low), + self.distance_to_resolution(_high), + ) + return self._limits + + def update_energy(self, energy_pos, wavelength_pos): + """Update the resolution when energy changed. + Args: + value(float): Energy [keV] + """ + logging.getLogger("HWR").debug( + "Energy changed, updating resolution and limits" + ) + + self._nominal_value = self.resedge.force_get_value() + self.value = self._nominal_value + self.get_limits() + self.emit("limitsChanged", (self._limits, )) + self.emit("valueChanged", (self._nominal_value,)) + + def update_state(self, state): + pass + + def update_distance(self, value=None): + """Update the resolution when distance changed. + Args: + value (float): Detector distance [mm]. + """ + self._nominal_value = self.resedge.force_get_value() + self.emit("valueChanged", (self._nominal_value,)) + + def get_value(self): + """Read the value. + Returns: + (float): value. + """ + self._nominal_value = self.resedge.force_get_value() + + return self._nominal_value + + def set_value(self, value, timeout = None): + distance = self.resolution_to_distance(value) + msg = "Move resolution to {} ({} mm)".format(value, distance) + logging.getLogger().info(msg) + self._hwr_detector.distance.set_value(distance) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocSardanaMotor.py b/mxcubecore/HardwareObjects/ALBA/XalocSardanaMotor.py new file mode 100755 index 0000000000..7973950d16 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocSardanaMotor.py @@ -0,0 +1,133 @@ +# encoding: utf-8 +# +# 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 General Lesser Public License +# along with MXCuBE. If not, see . + +from mxcubecore.HardwareObjects.abstract.AbstractMotor import ( + AbstractMotor, + MotorStates, +) +from mxcubecore.HardwareObjects.SardanaMotor import SardanaMotor +from gevent import Timeout +import time + +__copyright__ = """ Copyright © 2010-2020 by the MXCuBE collaboration """ +__license__ = "LGPLv3+" +__credits__ = ["ALBA"] +__version__ = "3." +__category__ = "General" + +class XalocSardanaMotor(SardanaMotor): + + def __init__(self, name): + AbstractMotor.__init__(self, name) + self.stop_command = None + self.position_channel = None + self.state_channel = None + self.taurusname = None + self.motor_position = 0.0 + self.last_position_emitted = 0.0 + self.threshold_default = 0.0018 + self.move_threshold_default = 0.0 + self.polling_default = "events" + self.limit_upper = None + self.limit_lower = None + self.static_limits = (-1e4, 1e4) + self.limits = (None, None) + #RB: critical bug, NOTINITIALIZED is not a valid MotorStates + #self.motor_state = MotorStates.NOTINITIALIZED + self.motor_state = MotorStates.INITIALIZING + + def init(self): + SardanaMotor.init(self) + + def motor_state_changed(self, state=None): + """ + Descript. : called by the state channels update event + checks if the motor is at it's limit, + and sets the new device state + """ + motor_state = self.motor_state + + if state is None: + state = self.state_channel.get_value() + + state = str(state).strip("DevState.") + motor_state = SardanaMotor.state_map[state] + + if motor_state != MotorStates.DISABLED: + if self.motor_position >= self.limit_upper: + motor_state = MotorStates.HIGHLIMIT + elif self.motor_position <= self.limit_lower: + motor_state = MotorStates.LOWLIMIT + + #self.set_ready(motor_state > MotorStates.DISABLED) + + if motor_state != self.motor_state: + self.motor_state = motor_state + self.emit("stateChanged", (motor_state,)) + + def get_limits(self): + """ + Descript. : returns motor limits. If no limits channel defined then + static_limits is returned + """ + try: + # RB: added the following three lines, since the limits were never properly initialized + info = self.position_channel.get_info() + self.limit_lower = info.minval + self.limit_upper = info.maxval + + return (self.limit_lower, self.limit_upper) + except Exception: + return (None, None) + + def is_ready(self): + return self.get_state() == MotorStates.READY + + def wait_ready(self, timeout=None): + """Wait timeout seconds till SardanaMotor is ready. + + if timeout is None: wait forever. + + Args: + timeout (s): + + Returns: + """ + with Timeout(timeout, RuntimeError("Timeout waiting for SardanaMotor status ready")): + while not self.is_ready(): + time.sleep(0.05) + + def motor_position_changed(self, position=None): + """ + Descript. : called by the position channels update event + if the position change exceeds threshold, + valueChanged is fired + """ + if position is None: + position = self.position_channel.get_value() + self.last_position_emitted = position + if abs(self.last_position_emitted - position) >= self.threshold: + self.motor_position = position + self.last_position_emitted = position + self.emit("valueChanged", (position,)) + self.motor_state_changed() + + + diff --git a/mxcubecore/HardwareObjects/ALBA/XalocSession.py b/mxcubecore/HardwareObjects/ALBA/XalocSession.py new file mode 100644 index 0000000000..25225ba74c --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocSession.py @@ -0,0 +1,175 @@ +# +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] +XalocSession + +[Description] +Specific HwObj to control user configuration. + +[Emitted signals] +- None +""" + +#from __future__ import print_function + +import os +import time +import logging +from Session import Session +import queue_model_objects + +__credits__ = ["ALBA"] +__version__ = "3." +__category__ = "General" + +# RB: refactored version uses PROCESSED_DATA, the previous version uses PROCESS_DATA for the processing dir +# might cause problems +#default_processed_data_folder = "PROCESS_DATA" + +class XalocSession(Session): + + def __init__(self, *args): + Session.__init__(self, *args) + self.logger = logging.getLogger("HWR.XalocSession") + self.senv = None + + def init(self): + Session.init(self) + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + self.senv = self.get_command_object("senv") + + def get_base_data_directory(self): + """ + Returns the base data directory for Xaloc + In Xaloc the base directory already includes the user + home directory. So + information into account, such as if the current user + is inhouse. + + :returns: The base data path. + :rtype: str + """ + if self.session_start_date: + start_time = self.session_start_date.split(' ')[0].replace('-', '') + else: + start_time = time.strftime("%Y%m%d") + + if self.base_directory is not None: + directory = os.path.join(self.base_directory, start_time) + else: + directory = '/tmp' + return directory + + def get_archive_directory(self, directory=None): + if directory is None: + _dir = self.get_base_data_directory() + else: + _dir = directory + + parts = _dir.split(os.path.sep) + try: + user_dir = parts[5] + session_date = parts[6] + except: + user_dir = parts[0] + session_date = parts[1] + # remove RAW_DATA from da + + + try: + more = parts[8:] + except Exception as e: + logging.getLogger('HWR').debug("%s" % str(e)) + more = [] + + archive_dir = os.path.join( + self.base_archive_directory, + user_dir, + session_date, + *more) + self.logger.debug("XalocSession. returning archive directory: %s" % archive_dir) + return archive_dir + + def set_ldap_homedir(self, homedir): + self.base_directory = homedir + self.base_process_directory = homedir + + queue_model_objects.PathTemplate.set_data_base_path(self.base_directory) + + def get_default_prefix(self, sample_data_node=None, generic_name=False): + """ + Returns the default prefix, using sample data such as the + acronym as parts in the prefix. + + :param sample_data_node: The data node to get additional + information from, (which will be + added to the prefix). + :type sample_data_node: Sample + + + :returns: The default prefix. + :rtype: str + """ + proposal = self.get_proposal() + prefix = proposal + + if sample_data_node: + if sample_data_node.has_lims_data(): + protein_acronym = sample_data_node.crystals[0].protein_acronym + name = sample_data_node.name + if protein_acronym: + if name: + if self.proposal_number.split('-')[-1] in ['2019013247','2018002222']: + prefix = "%s" % (name) + else: + prefix = "%s-%s" % (protein_acronym, name) + else: + prefix = protein_acronym + else: + prefix = name or "" + else: + try: + prefix = "B{0}X{1}".format(*sample_data_node.get_name().split(":")) + except Exception: + prefix = str(sample_data_node.get_name()) + + elif generic_name: + prefix = "-" + # + return prefix + + def set_sardana_collect_env(self, MXCollectDir = None, MXCollectPrefix = None, MXRunNumber = None): + if MXCollectDir != None: + self.senv('MXCollectDir', MXCollectDir, wait=True) + if MXCollectPrefix != None: + self.senv('MXCollectPrefix', MXCollectPrefix, wait=True) + if MXRunNumber != None: + self.senv('MXRunNumber', MXRunNumber, wait=True) + + + +def test_hwo(hwo): + print('Base data directory: %s' % hwo.get_base_data_directory()) + print('Base Image directory: %s' % hwo.get_base_image_directory()) + print('Image directory: %s' % hwo.get_image_directory()) + print('Base Process directory: %s' % hwo.get_base_process_directory()) + print('Process directory: %s' % hwo.get_process_directory()) + print('Archive directory: %s' % hwo.get_archive_directory()) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocSupervisor.py b/mxcubecore/HardwareObjects/ALBA/XalocSupervisor.py new file mode 100755 index 0000000000..c0696e3ab3 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocSupervisor.py @@ -0,0 +1,233 @@ +# +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] +XalocSupervisor + +[Description] +Specific HwObj to interface the Beamline Supervisor TangoDS + +[Emitted signals] +- stateChanged +- phaseChanged +""" + +from __future__ import print_function + +import logging +import time + +from mxcubecore.BaseHardwareObjects import Device +from taurus.core.tango.enums import DevState +from mxcubecore.HardwareObjects import GenericDiffractometer + +from mxcubecore import HardwareRepository as HWR + +__credits__ = ["ALBA"] +__version__ = "3." +__category__ = "General" +__author__ = "Roeland Boer, Jordi Andreu" + +class XalocSupervisor(Device): + + def __init__(self, *args): + Device.__init__(self, *args) + self.logger = logging.getLogger("HWR.XalocSupervisor") + self.user_level_log = logging.getLogger("user_level_log") + + self.cmd_go_collect = None + self.cmd_go_sample_view = None + self.cmd_go_transfer = None + self.cmd_go_beam_view = None + self.chan_state = None + self.chan_phase = None + self.chan_detector_cover = None + + self.current_state = None + self.current_phase = None + self.detector_cover_opened = None + + self.phase_list = [] + + def init(self): + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + self.cmd_go_collect = self.get_command_object("go_collect") + self.cmd_go_sample_view = self.get_command_object("go_sample_view") + self.cmd_go_transfer = self.get_command_object("go_transfer") + self.cmd_go_beam_view = self.get_command_object("go_beam_view") + self.chan_state = self.get_channel_object("state") + self.chan_phase = self.get_channel_object("phase") + self.chan_detector_cover = self.get_channel_object("detector_cover_open") + #self.chan_fast_shutter_collect_position = self.get_channel_object("FastShutCollectPosition") + + try: + self.phase_list = eval(self.get_property("phase_list")) + except Exception: + self.phase_list = [ + GenericDiffractometer.PHASE_TRANSFER, + GenericDiffractometer.PHASE_CENTRING, + GenericDiffractometer.PHASE_COLLECTION, + GenericDiffractometer.PHASE_BEAM, + ] + + self.chan_state.connect_signal("update", self.state_changed) + self.chan_phase.connect_signal("update", self.phase_changed) + self.chan_detector_cover.connect_signal("update", self.detector_cover_changed) + + self.logger.debug("Supervisor state: {0}".format(self.current_state)) + self.logger.debug("Supervisor phase: {0}".format(self.current_phase)) + + #def isReady(self): + #return True + + #def getUserName(self): + #return self.username + + def state_changed(self, value): + self.current_state = value + self.emit('stateChanged', self.current_state) + + def phase_changed(self, value): + # TODO: Define supervisor states with enum + if value == 'Sample': + value = 'Centring' + self.current_phase = value + self.emit('phaseChanged', self.current_phase) + + def get_current_phase(self): + try: + _value = self.chan_phase.get_value() + #self.logger.debug('get_current_phase: (value={0}, type={1})'.format(_value, type(_value))) + except Exception as e: + raise RuntimeError('Cannot get supervisor current phase:\n%s' % str(e)) + return _value + # return self.chan_phase.get_value() + + def go_collect(self): + return self.cmd_go_collect() + + def go_transfer(self): + return self.cmd_go_transfer() + + def go_sample_view(self): + return self.cmd_go_sample_view() + + def go_beam_view(self): + return self.cmd_go_beam_view() + + + def get_phase(self): + return self.current_phase + + def get_phase_list(self): + """ + Returns list of available phases + + :returns: list with str + """ + return self.phase_list + + def get_state(self): + try: + _value = self.chan_state.get_value() + #self.logger.debug('get_state: (value={0}, type={1})'.format(_value, type(_value))) + except Exception as e: + raise RuntimeError('Cannot get supervisor state:\n%s' % str(e)) + return _value + #return self.chan_state.get_value() + + def detector_cover_changed(self, value): + self.detector_cover_opened = value + + def open_detector_cover(self): + self.chan_detector_cover.set_value(True) + + def close_detector_cover(self): + self.chan_detector_cover.set_value(False) + + def is_detector_cover_opened(self): + return self.chan_detector_cover.get_value() + + def is_fast_shutter_in_collect_position(self): + return self.chan_fast_shutter_collect_position.get_value() + + def wait_ready(self, timeout = 30): + stime = time.time() + while True: + if self.current_state == DevState.ON: + self.logger.debug("Supervisor is in ON state. Returning") + break + time.sleep(0.2) + if timeout is not None: + if time.time() - stime > timeout: + raise Exception("Supervisor timed out waiting for ON state") + + def set_phase(self, phase, timeout=None): + #TODO: implement timeout. Current API to fulfill the API. + """ + General function to set phase by using supervisor commands. + """ + + self.logger.debug("Current supervisor phase is %s" % self.current_phase) + if phase.upper() == self.current_phase.upper(): + self.logger.warning("Suprevisor already in phase %s" % phase) + return + + if phase.upper() != "TRANSFER" and HWR.beamline.ln2shower.is_pumping(): + msg = "Cannot change to non transfer phase when the lnshower is pumping, turn off the shower first" + self.user_level_log.error(msg) + raise Exception(msg) + + if self.current_state != DevState.ON: + msg = "Cannot change to phase %s, supervisor is not ready, state is %s" % ( phase, self.current_state ) + self.user_level_log.error(msg) + raise Exception(msg) + + if phase.upper() == "TRANSFER": + self.go_transfer() + elif phase.upper() == "COLLECT": + self.go_collect() + elif phase.upper() == "BEAMVIEW": + self.go_beam_view() + elif phase.upper() == "CENTRING": + self.go_sample_view() + else: + self.logger.warning( + "Supervisor set_phase asked for un-handled phase: %s" % phase + ) + return + + self.logger.debug( + "Telling supervisor to go to phase %s, with timeout %s" % ( phase, timeout ) + ) + + if timeout: + time.sleep(1) + self.wait_ready( timeout = timeout ) + time.sleep(1) + self.logger.debug( + "Supervisor phase is %s" % ( self.get_phase() ) + ) + +def test_hwo(hwo): + print("Supervisor control \"%s\"\n" % hwo.getUserName()) + print("Is Detector Cover open?:", hwo.is_detector_cover_opened()) + print("Current Phase is:", hwo.get_current_phase()) + print("Current State is:", hwo.get_state()) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocTransmission.py b/mxcubecore/HardwareObjects/ALBA/XalocTransmission.py new file mode 100644 index 0000000000..1b91b13b18 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocTransmission.py @@ -0,0 +1,153 @@ +# +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] +XalocTransmission + +[Description] +Specific HwObj to setup the beamline transmission + +[Emitted signals] +- valueChanged +- stateChanged +""" + +#from __future__ import print_function + +import logging + +from mxcubecore.BaseHardwareObjects import Device, HardwareObjectState +from mxcubecore import HardwareRepository as HWR + +__credits__ = ["ALBA"] +__version__ = "3" +__category__ = "General" + + +class XalocTransmission(Device): + + #Taurus 4.1.1 DevState + #ALARM = 11 + #CLOSE = 2 + #DISABLE = 12 + #EXTRACT = 5 + #FAULT = 8 + #INIT = 9 + #INSERT = 4 + #MOVING = 6 + #OFF = 1 + #ON = 0 + #OPEN = 3 + #RUNNING = 10 + #STANDBY = 7 + #UNKNOWN = 13 + + # BaseHardwareObjects.HardwareObjectState(enum.Enum): + #UNKNOWN = 0 + #WARNING = 1 + #BUSY = 2 + #READY = 3 + #FAULT = 4 + #OFF = 5 + + Tango2HWO_State = [ + HardwareObjectState.READY, # 0 DevState.ON + HardwareObjectState.OFF, # 1 DevState.OFF + HardwareObjectState.READY, # 2 DevState.CLOSE + HardwareObjectState.READY, # 3 DevState.OPEN + HardwareObjectState.BUSY, # 4 DevState.INSERT + HardwareObjectState.BUSY, # 5 DevState.EXTRACT + HardwareObjectState.BUSY, # 6 DevState.MOVING + HardwareObjectState.READY, # 7 DevState.STANDBY + HardwareObjectState.FAULT, # 8 DevState.FAULT + HardwareObjectState.BUSY, # 9 DevState.INIT + HardwareObjectState.BUSY, # 10 DevState.RUNNING + HardwareObjectState.FAULT, # 11 DevState.ALARM + HardwareObjectState.OFF, # 12 DevState.DISABLE + HardwareObjectState.UNKNOWN # 13 DevState.UNKNOWN + ] + + def __init__(self, *args): + Device.__init__(self, *args) + self.logger = logging.getLogger("HWR.XalocTransmission") + self.chan_transmission = None + self.chan_state = None + + def init(self): + self.logger.debug("Initializing {0}".format(self.__class__.__name__)) + self.chan_transmission = self.get_channel_object("transmission") + self.chan_state = self.get_channel_object("state") + + self.chan_transmission.connect_signal("update", self.update_values) + self.chan_state.connect_signal("update", self.state_changed) + + self.update_values() + + if HWR.beamline.energy is not None: + HWR.beamline.energy.connect("energyChanged", self.energy_changed ) + + def is_ready(self): + return True + + def transmission_changed(self, value): + self.emit('valueChanged', value) + + def state_changed(self, value): + #TODO: translate DevState to Hardware Object states + + self.emit('stateChanged', self.Tango2HWO_State[ value ] ) + + #def getAttState(self): + #self.state = self.chan_state.get_value() + #return self.state + + #def getAttFactor(self): + #return self.get_value() + + def get_value(self, force=False): + if force: + return self.chan_transmission.force_get_value() + else: + return self.chan_transmission.get_value() + + def get_state(self): + return self.chan_state.get_value() + + def set_value(self, value): + self.chan_transmission.set_value(value) + + def set_transmission(self, value): + self.set_value(value) + + def update_values(self, force=False): + value = self.get_value(force) + self.transmission_changed( value ) + state = self.get_state() + self.state_changed( state ) + + def energy_changed(self, energy_position, wavelength_position): + #self.update_values() + if HWR.beamline.energy.is_ready(): + self.logger.debug("Reading transmission after energy change") + self.update_values(force = True) + +def test_hwo(hwo): + print("Transmission is: ", hwo.get_value()) + print("Transmission state is: ", hwo.getAttState()) diff --git a/mxcubecore/HardwareObjects/ALBA/XalocXSDataAutoprocv1_0.py b/mxcubecore/HardwareObjects/ALBA/XalocXSDataAutoprocv1_0.py new file mode 100755 index 0000000000..cc8574c20c --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocXSDataAutoprocv1_0.py @@ -0,0 +1,101 @@ +# +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MXCuBE. If not, see . + +""" +[Name] XalocXSDataAutoprocInput + +[Description] +Extending XSDataAutoprocInput to allow doAnomNonanom and xia2 with small molecule + +[Signals] +- None +""" + +from XSDataAutoprocv1_0 import XSDataAutoprocInput + +class XalocXSDataAutoprocInput(XSDataAutoprocInput): + + def __init__( + self, + configuration=None, + output_file=None, + unit_cell=None, + spacegroup=None, + nres=None, + low_resolution_limit=None, + detector_max_res=None, + data_collection_id=None, + cc_half_cutoff=None, + r_value_cutoff=None, + isig_cutoff=None, + completeness_cutoff=None, + res_override=None, + input_file=None, + setDoAnomAndNonanom=None, + ): + XSDataAutoprocInput.__init__( + self, + configuration=None, + output_file=None, + unit_cell=None, + spacegroup=None, + nres=None, + low_resolution_limit=None, + detector_max_res=None, + data_collection_id=None, + cc_half_cutoff=None, + r_value_cutoff=None, + isig_cutoff=None, + completeness_cutoff=None, + res_override=None, + input_file=None, + ) + + if setDoAnomAndNonanom is None: + self._doAnomAndNonanom = None + elif setDoAnomAndNonanom.__class__.__name__ == "XSDataBoolean": + self._doAnomAndNonanom = doAnomAndNonanom + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'doAnomAndNonanom' is not XSDataBoolean but %s" % doAnomAndNonanom.__class__.__name__ + raise BaseException(strMessage) + + # Methods and properties for the 'doAnomAndNonanom' attribute, recovered from previous mxcube version + def getDoAnomAndNonanom(self): return self._doAnomAndNonanom + def setDoAnomAndNonanom(self, doAnomAndNonanom): + if doAnomAndNonanom is None: + self._doAnomAndNonanom = None + elif doAnomAndNonanom.__class__.__name__ == "XSDataBoolean": + self._doAnomAndNonanom = doAnomAndNonanom + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setDoAnomAndNonanom argument is not XSDataBoolean but %s" % doAnomAndNonanom.__class__.__name__ + raise BaseException(strMessage) + def delDoAnomAndNonanom(self): self._doAnomAndNonanom = None + + #def exportChildren(self, outfile, level, name_="XSDataAutoprocInput"): + #if self._doAnomAndNonanom is not None: + #self.doAnomAndNonanom.export(outfile, level, name_='doAnomAndNonanom') + #XSDataAutoprocInput.exportChildren(self, outfile, level, name_) + + + def exportChildren(self, outfile, level, name_="XSDataAutoprocInput"): + XSDataAutoprocInput.exportChildren(self, outfile, level, name_) + if self._doAnomAndNonanom is not None: + self._doAnomAndNonanom.export(outfile, level, name_='doAnomAndNonanom') + + doAnomAndNonanom = property(getDoAnomAndNonanom, setDoAnomAndNonanom, delDoAnomAndNonanom, "Property for doAnomAndNonanom") diff --git a/mxcubecore/HardwareObjects/ALBA/XalocXSDataControlAutoPROCv1_0.py b/mxcubecore/HardwareObjects/ALBA/XalocXSDataControlAutoPROCv1_0.py new file mode 100644 index 0000000000..dd1b43342f --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocXSDataControlAutoPROCv1_0.py @@ -0,0 +1,511 @@ +#!/usr/bin/env python + +# +# Generated Mon Feb 5 08:54::10 2018 by EDGenerateDS. +# + +import os, sys +from xml.dom import minidom +from xml.dom import Node + + +strEdnaHome = os.environ.get("EDNA_HOME", None) + +dictLocation = { \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ +} + +try: + from XSDataCommon import XSDataBoolean + from XSDataCommon import XSDataFile + from XSDataCommon import XSDataInput + from XSDataCommon import XSDataInteger + from XSDataCommon import XSDataResult + from XSDataCommon import XSDataString +except ImportError as error: + if strEdnaHome is not None: + for strXsdName in dictLocation: + strXsdModule = strXsdName + ".py" + strRootdir = os.path.dirname(os.path.abspath(os.path.join(strEdnaHome, dictLocation[strXsdName]))) + for strRoot, listDirs, listFiles in os.walk(strRootdir): + if strXsdModule in listFiles: + sys.path.append(strRoot) + else: + raise error +from XSDataCommon import XSDataBoolean +from XSDataCommon import XSDataFile +from XSDataCommon import XSDataInput +from XSDataCommon import XSDataInteger +from XSDataCommon import XSDataResult +from XSDataCommon import XSDataString + + + + +# +# Support/utility functions. +# + +# Compabiltity between Python 2 and 3: +if sys.version.startswith('3'): + unicode = str + from io import StringIO +else: + from StringIO import StringIO + + +def showIndent(outfile, level): + for idx in range(level): + outfile.write(unicode(' ')) + + +def warnEmptyAttribute(_strName, _strTypeName): + pass + #if not _strTypeName in ["float", "double", "string", "boolean", "integer"]: + # print("Warning! Non-optional attribute %s of type %s is None!" % (_strName, _strTypeName)) + +class MixedContainer(object): + # Constants for category: + CategoryNone = 0 + CategoryText = 1 + CategorySimple = 2 + CategoryComplex = 3 + # Constants for content_type: + TypeNone = 0 + TypeText = 1 + TypeString = 2 + TypeInteger = 3 + TypeFloat = 4 + TypeDecimal = 5 + TypeDouble = 6 + TypeBoolean = 7 + def __init__(self, category, content_type, name, value): + self.category = category + self.content_type = content_type + self.name = name + self.value = value + def getCategory(self): + return self.category + def getContenttype(self, content_type): + return self.content_type + def getValue(self): + return self.value + def getName(self): + return self.name + def export(self, outfile, level, name): + if self.category == MixedContainer.CategoryText: + outfile.write(self.value) + elif self.category == MixedContainer.CategorySimple: + self.exportSimple(outfile, level, name) + else: # category == MixedContainer.CategoryComplex + self.value.export(outfile, level, name) + def exportSimple(self, outfile, level, name): + if self.content_type == MixedContainer.TypeString: + outfile.write(unicode('<%s>%s' % (self.name, self.value, self.name))) + elif self.content_type == MixedContainer.TypeInteger or \ + self.content_type == MixedContainer.TypeBoolean: + outfile.write(unicode('<%s>%d' % (self.name, self.value, self.name))) + elif self.content_type == MixedContainer.TypeFloat or \ + self.content_type == MixedContainer.TypeDecimal: + outfile.write(unicode('<%s>%f' % (self.name, self.value, self.name))) + elif self.content_type == MixedContainer.TypeDouble: + outfile.write(unicode('<%s>%g' % (self.name, self.value, self.name))) + +# +# Data representation classes. +# + + + +class XalocXSDataInputControlAutoPROC(XSDataInput): + def __init__(self, configuration=None, cell=None, symm=None, doAnomAndNonanom=None, processDirectory=None, toN=None, fromN=None, templateN=None, configDef=None, dirN=None, dataCollectionId=None): + XSDataInput.__init__(self, configuration) + if dataCollectionId is None: + self._dataCollectionId = None + elif dataCollectionId.__class__.__name__ == "XSDataInteger": + self._dataCollectionId = dataCollectionId + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'dataCollectionId' is not XSDataInteger but %s" % self._dataCollectionId.__class__.__name__ + raise BaseException(strMessage) + if dirN is None: + self._dirN = None + elif dirN.__class__.__name__ == "XSDataFile": + self._dirN = dirN + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'dirN' is not XSDataFile but %s" % self._dirN.__class__.__name__ + raise BaseException(strMessage) + if configDef is None: + self._configDef = None + elif configDef.__class__.__name__ == "XSDataFile": + self._configDef = configDef + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'configDef' is not XSDataFile but %s" % self._configDef.__class__.__name__ + raise BaseException(strMessage) + if templateN is None: + self._templateN = None + elif templateN.__class__.__name__ == "XSDataString": + self._templateN = templateN + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'templateN' is not XSDataString but %s" % self._templateN.__class__.__name__ + raise BaseException(strMessage) + if fromN is None: + self._fromN = None + elif fromN.__class__.__name__ == "XSDataInteger": + self._fromN = fromN + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'fromN' is not XSDataInteger but %s" % self._fromN.__class__.__name__ + raise BaseException(strMessage) + if toN is None: + self._toN = None + elif toN.__class__.__name__ == "XSDataInteger": + self._toN = toN + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'toN' is not XSDataInteger but %s" % self._toN.__class__.__name__ + raise BaseException(strMessage) + if processDirectory is None: + self._processDirectory = None + elif processDirectory.__class__.__name__ == "XSDataFile": + self._processDirectory = processDirectory + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'processDirectory' is not XSDataFile but %s" % self._processDirectory.__class__.__name__ + raise BaseException(strMessage) + if doAnomAndNonanom is None: + self._doAnomAndNonanom = None + elif doAnomAndNonanom.__class__.__name__ == "XSDataBoolean": + self._doAnomAndNonanom = doAnomAndNonanom + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'doAnomAndNonanom' is not XSDataBoolean but %s" % self._doAnomAndNonanom.__class__.__name__ + raise BaseException(strMessage) + if symm is None: + self._symm = None + elif symm.__class__.__name__ == "XSDataString": + self._symm = symm + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'symm' is not XSDataString but %s" % self._symm.__class__.__name__ + raise BaseException(strMessage) + if cell is None: + self._cell = None + elif cell.__class__.__name__ == "XSDataString": + self._cell = cell + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'cell' is not XSDataString but %s" % self._cell.__class__.__name__ + raise BaseException(strMessage) + # Methods and properties for the 'dataCollectionId' attribute + def getDataCollectionId(self): return self._dataCollectionId + def setDataCollectionId(self, dataCollectionId): + if dataCollectionId is None: + self._dataCollectionId = None + elif dataCollectionId.__class__.__name__ == "XSDataInteger": + self._dataCollectionId = dataCollectionId + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setDataCollectionId argument is not XSDataInteger but %s" % dataCollectionId.__class__.__name__ + raise BaseException(strMessage) + def delDataCollectionId(self): self._dataCollectionId = None + dataCollectionId = property(getDataCollectionId, setDataCollectionId, delDataCollectionId, "Property for dataCollectionId") + # Methods and properties for the 'dirN' attribute + def getDirN(self): return self._dirN + def setDirN(self, dirN): + if dirN is None: + self._dirN = None + elif dirN.__class__.__name__ == "XSDataFile": + self._dirN = dirN + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setDirN argument is not XSDataFile but %s" % dirN.__class__.__name__ + raise BaseException(strMessage) + def delDirN(self): self._dirN = None + dirN = property(getDirN, setDirN, delDirN, "Property for dirN") + # Methods and properties for the 'configDef' attribute + def getConfigDef(self): return self._configDef + def setConfigDef(self, configDef): + if configDef is None: + self._configDef = None + elif configDef.__class__.__name__ == "XSDataFile": + self._configDef = configDef + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setDirN argument is not XSDataFile but %s" % configDef.__class__.__name__ + raise BaseException(strMessage) + def delConfigDef(self): self._configDef = None + configDef = property(getConfigDef, setConfigDef, delConfigDef, "Property for configDef") + # Methods and properties for the 'templateN' attribute + def getTemplateN(self): return self._templateN + def setTemplateN(self, templateN): + if templateN is None: + self._templateN = None + elif templateN.__class__.__name__ == "XSDataString": + self._templateN = templateN + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setTemplateN argument is not XSDataString but %s" % templateN.__class__.__name__ + raise BaseException(strMessage) + def delTemplateN(self): self._templateN = None + templateN = property(getTemplateN, setTemplateN, delTemplateN, "Property for templateN") + # Methods and properties for the 'fromN' attribute + def getFromN(self): return self._fromN + def setFromN(self, fromN): + if fromN is None: + self._fromN = None + elif fromN.__class__.__name__ == "XSDataInteger": + self._fromN = fromN + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setFromN argument is not XSDataInteger but %s" % fromN.__class__.__name__ + raise BaseException(strMessage) + def delFromN(self): self._fromN = None + fromN = property(getFromN, setFromN, delFromN, "Property for fromN") + # Methods and properties for the 'toN' attribute + def getToN(self): return self._toN + def setToN(self, toN): + if toN is None: + self._toN = None + elif toN.__class__.__name__ == "XSDataInteger": + self._toN = toN + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setToN argument is not XSDataInteger but %s" % toN.__class__.__name__ + raise BaseException(strMessage) + def delToN(self): self._toN = None + toN = property(getToN, setToN, delToN, "Property for toN") + # Methods and properties for the 'processDirectory' attribute + def getProcessDirectory(self): return self._processDirectory + def setProcessDirectory(self, processDirectory): + if processDirectory is None: + self._processDirectory = None + elif processDirectory.__class__.__name__ == "XSDataFile": + self._processDirectory = processDirectory + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setProcessDirectory argument is not XSDataFile but %s" % processDirectory.__class__.__name__ + raise BaseException(strMessage) + def delProcessDirectory(self): self._processDirectory = None + processDirectory = property(getProcessDirectory, setProcessDirectory, delProcessDirectory, "Property for processDirectory") + # Methods and properties for the 'doAnomAndNonanom' attribute + def getDoAnomAndNonanom(self): return self._doAnomAndNonanom + def setDoAnomAndNonanom(self, doAnomAndNonanom): + if doAnomAndNonanom is None: + self._doAnomAndNonanom = None + elif doAnomAndNonanom.__class__.__name__ == "XSDataBoolean": + self._doAnomAndNonanom = doAnomAndNonanom + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setDoAnomAndNonanom argument is not XSDataBoolean but %s" % doAnomAndNonanom.__class__.__name__ + raise BaseException(strMessage) + def delDoAnomAndNonanom(self): self._doAnomAndNonanom = None + doAnomAndNonanom = property(getDoAnomAndNonanom, setDoAnomAndNonanom, delDoAnomAndNonanom, "Property for doAnomAndNonanom") + # Methods and properties for the 'symm' attribute + def getSpacegroup(self): return self._symm + def setSpacegroup(self, symm): + if symm is None: + self._symm = None + elif symm.__class__.__name__ == "XSDataString": + self._symm = symm + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setSymm argument is not XSDataString but %s" % symm.__class__.__name__ + raise BaseException(strMessage) + def delSpacegroup(self): self._symm = None + symm = property(getSpacegroup, setSpacegroup, delSpacegroup, "Property for symm") + # Methods and properties for the 'cell' attribute + def getUnit_cell(self): return self._cell + def setUnit_cell(self, cell): + if cell is None: + self._cell = None + elif cell.__class__.__name__ == "XSDataString": + self._cell = cell + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setCell argument is not XSDataString but %s" % cell.__class__.__name__ + raise BaseException(strMessage) + def delUnit_cell(self): self._cell = None + unit_cell = property(getUnit_cell, setUnit_cell, delUnit_cell, "Property for cell") + def export(self, outfile, level, name_='XSDataInputControlAutoPROC'): + showIndent(outfile, level) + outfile.write(unicode('<%s>\n' % name_)) + self.exportChildren(outfile, level + 1, name_) + showIndent(outfile, level) + outfile.write(unicode('\n' % name_)) + def exportChildren(self, outfile, level, name_='XSDataInputControlAutoPROC'): + XSDataInput.exportChildren(self, outfile, level, name_) + if self._dataCollectionId is not None: + self.dataCollectionId.export(outfile, level, name_='dataCollectionId') + if self._dirN is not None: + self.dirN.export(outfile, level, name_='dirN') + if self._configDef is not None: + self.configDef.export(outfile, level, name_='configDef') + if self._templateN is not None: + self.templateN.export(outfile, level, name_='templateN') + if self._fromN is not None: + self.fromN.export(outfile, level, name_='fromN') + if self._toN is not None: + self.toN.export(outfile, level, name_='toN') + if self._processDirectory is not None: + self.processDirectory.export(outfile, level, name_='processDirectory') + if self._doAnomAndNonanom is not None: + self.doAnomAndNonanom.export(outfile, level, name_='doAnomAndNonanom') + if self._symm is not None: + self.symm.export(outfile, level, name_='symm') + if self._cell is not None: + self._cell.export(outfile, level, name_='cell') + def build(self, node_): + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'dataCollectionId': + obj_ = XSDataInteger() + obj_.build(child_) + self.setDataCollectionId(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'dirN': + obj_ = XSDataFile() + obj_.build(child_) + self.setDirN(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'configDef': + obj_ = XSDataFile() + obj_.build(child_) + self.setConfigDef(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'templateN': + obj_ = XSDataString() + obj_.build(child_) + self.setTemplateN(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'fromN': + obj_ = XSDataInteger() + obj_.build(child_) + self.setFromN(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'toN': + obj_ = XSDataInteger() + obj_.build(child_) + self.setToN(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'processDirectory': + obj_ = XSDataFile() + obj_.build(child_) + self.setProcessDirectory(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'doAnomAndNonanom': + obj_ = XSDataBoolean() + obj_.build(child_) + self.setDoAnomAndNonanom(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'symm': + obj_ = XSDataString() + obj_.build(child_) + self.setSymm(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'cell': + obj_ = XSDataString() + obj_.build(child_) + self.setCell(obj_) + XSDataInput.buildChildren(self, child_, nodeName_) + #Method for marshalling an object + def marshal( self ): + oStreamString = StringIO() + oStreamString.write(unicode('\n')) + self.export( oStreamString, 0, name_="XSDataInputControlAutoPROC" ) + oStringXML = oStreamString.getvalue() + oStreamString.close() + return oStringXML + #Only to export the entire XML tree to a file stream on disk + def exportToFile( self, _outfileName ): + outfile = open( _outfileName, "w" ) + outfile.write(unicode('\n')) + self.export( outfile, 0, name_='XSDataInputControlAutoPROC' ) + outfile.close() + #Deprecated method, replaced by exportToFile + def outputFile( self, _outfileName ): + print("WARNING: Method outputFile in class XSDataInputControlAutoPROC is deprecated, please use instead exportToFile!") + self.exportToFile(_outfileName) + #Method for making a copy in a new instance + def copy( self ): + return XSDataInputControlAutoPROC.parseString(self.marshal()) + #Static method for parsing a string + def parseString( _inString ): + doc = minidom.parseString(_inString) + rootNode = doc.documentElement + rootObj = XSDataInputControlAutoPROC() + rootObj.build(rootNode) + # Check that all minOccurs are obeyed by marshalling the created object + oStreamString = StringIO() + rootObj.export( oStreamString, 0, name_="XSDataInputControlAutoPROC" ) + oStreamString.close() + return rootObj + parseString = staticmethod( parseString ) + #Static method for parsing a file + def parseFile( _inFilePath ): + doc = minidom.parse(_inFilePath) + rootNode = doc.documentElement + rootObj = XSDataInputControlAutoPROC() + rootObj.build(rootNode) + return rootObj + parseFile = staticmethod( parseFile ) +# end class XSDataInputControlAutoPROC + + +class XSDataResultControlAutoPROC(XSDataResult): + def __init__(self, status=None): + XSDataResult.__init__(self, status) + def export(self, outfile, level, name_='XSDataResultControlAutoPROC'): + showIndent(outfile, level) + outfile.write(unicode('<%s>\n' % name_)) + self.exportChildren(outfile, level + 1, name_) + showIndent(outfile, level) + outfile.write(unicode('\n' % name_)) + def exportChildren(self, outfile, level, name_='XSDataResultControlAutoPROC'): + XSDataResult.exportChildren(self, outfile, level, name_) + def build(self, node_): + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildChildren(self, child_, nodeName_): + pass + XSDataResult.buildChildren(self, child_, nodeName_) + #Method for marshalling an object + def marshal( self ): + oStreamString = StringIO() + oStreamString.write(unicode('\n')) + self.export( oStreamString, 0, name_="XSDataResultControlAutoPROC" ) + oStringXML = oStreamString.getvalue() + oStreamString.close() + return oStringXML + #Only to export the entire XML tree to a file stream on disk + def exportToFile( self, _outfileName ): + outfile = open( _outfileName, "w" ) + outfile.write(unicode('\n')) + self.export( outfile, 0, name_='XSDataResultControlAutoPROC' ) + outfile.close() + #Deprecated method, replaced by exportToFile + def outputFile( self, _outfileName ): + print("WARNING: Method outputFile in class XSDataResultControlAutoPROC is deprecated, please use instead exportToFile!") + self.exportToFile(_outfileName) + #Method for making a copy in a new instance + def copy( self ): + return XSDataResultControlAutoPROC.parseString(self.marshal()) + #Static method for parsing a string + def parseString( _inString ): + doc = minidom.parseString(_inString) + rootNode = doc.documentElement + rootObj = XSDataResultControlAutoPROC() + rootObj.build(rootNode) + # Check that all minOccurs are obeyed by marshalling the created object + oStreamString = StringIO() + rootObj.export( oStreamString, 0, name_="XSDataResultControlAutoPROC" ) + oStreamString.close() + return rootObj + parseString = staticmethod( parseString ) + #Static method for parsing a file + def parseFile( _inFilePath ): + doc = minidom.parse(_inFilePath) + rootNode = doc.documentElement + rootObj = XSDataResultControlAutoPROC() + rootObj.build(rootNode) + return rootObj + parseFile = staticmethod( parseFile ) +# end class XSDataResultControlAutoPROC + + + +# End of data representation classes. + + diff --git a/mxcubecore/HardwareObjects/ALBA/XalocXSDataControlAutoPROCv1_1.py b/mxcubecore/HardwareObjects/ALBA/XalocXSDataControlAutoPROCv1_1.py new file mode 100644 index 0000000000..42470b47b3 --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocXSDataControlAutoPROCv1_1.py @@ -0,0 +1,1044 @@ +#!/usr/bin/env python + +# +# Generated Wed Jul 3 05:01::57 2019 by EDGenerateDS. +# + +import os, sys +from xml.dom import minidom +from xml.dom import Node + + +strEdnaHome = os.environ.get("EDNA_HOME", None) + +dictLocation = { \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ +} + +try: + from XSDataCommon import XSDataBoolean + from XSDataCommon import XSDataDouble + from XSDataCommon import XSDataFile + from XSDataCommon import XSDataInput + from XSDataCommon import XSDataInteger + from XSDataCommon import XSDataResult + from XSDataCommon import XSDataString +except ImportError as error: + if strEdnaHome is not None: + for strXsdName in dictLocation: + strXsdModule = strXsdName + ".py" + strRootdir = os.path.dirname(os.path.abspath(os.path.join(strEdnaHome, dictLocation[strXsdName]))) + for strRoot, listDirs, listFiles in os.walk(strRootdir): + if strXsdModule in listFiles: + sys.path.append(strRoot) + else: + raise error +from XSDataCommon import XSDataBoolean +from XSDataCommon import XSDataDouble +from XSDataCommon import XSDataFile +from XSDataCommon import XSDataInput +from XSDataCommon import XSDataInteger +from XSDataCommon import XSDataResult +from XSDataCommon import XSDataString + + + + +# +# Support/utility functions. +# + +# Compabiltity between Python 2 and 3: +if sys.version.startswith('3'): + unicode = str + from io import StringIO +else: + from StringIO import StringIO + + +def showIndent(outfile, level): + for idx in range(level): + outfile.write(unicode(' ')) + + +def warnEmptyAttribute(_strName, _strTypeName): + pass + #if not _strTypeName in ["float", "double", "string", "boolean", "integer"]: + # print("Warning! Non-optional attribute %s of type %s is None!" % (_strName, _strTypeName)) + +class MixedContainer(object): + # Constants for category: + CategoryNone = 0 + CategoryText = 1 + CategorySimple = 2 + CategoryComplex = 3 + # Constants for content_type: + TypeNone = 0 + TypeText = 1 + TypeString = 2 + TypeInteger = 3 + TypeFloat = 4 + TypeDecimal = 5 + TypeDouble = 6 + TypeBoolean = 7 + def __init__(self, category, content_type, name, value): + self.category = category + self.content_type = content_type + self.name = name + self.value = value + def getCategory(self): + return self.category + def getContenttype(self, content_type): + return self.content_type + def getValue(self): + return self.value + def getName(self): + return self.name + def export(self, outfile, level, name): + if self.category == MixedContainer.CategoryText: + outfile.write(self.value) + elif self.category == MixedContainer.CategorySimple: + self.exportSimple(outfile, level, name) + else: # category == MixedContainer.CategoryComplex + self.value.export(outfile, level, name) + def exportSimple(self, outfile, level, name): + if self.content_type == MixedContainer.TypeString: + outfile.write(unicode('<%s>%s' % (self.name, self.value, self.name))) + elif self.content_type == MixedContainer.TypeInteger or \ + self.content_type == MixedContainer.TypeBoolean: + outfile.write(unicode('<%s>%d' % (self.name, self.value, self.name))) + elif self.content_type == MixedContainer.TypeFloat or \ + self.content_type == MixedContainer.TypeDecimal: + outfile.write(unicode('<%s>%f' % (self.name, self.value, self.name))) + elif self.content_type == MixedContainer.TypeDouble: + outfile.write(unicode('<%s>%g' % (self.name, self.value, self.name))) + +# +# Data representation classes. +# + + + +class XSDataInputControlAutoPROC(XSDataInput): + def __init__(self, configuration=None, highResolutionLimit=None, lowResolutionLimit=None, reprocess=None, cell=None, symm=None, doAnomAndNonanom=None, doAnom=None, processDirectory=None, toN=None, fromN=None, templateN=None, dirN=None, dataCollectionId=None, configDef=None): + XSDataInput.__init__(self, configuration) + if dataCollectionId is None: + self._dataCollectionId = None + elif dataCollectionId.__class__.__name__ == "XSDataInteger": + self._dataCollectionId = dataCollectionId + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'dataCollectionId' is not XSDataInteger but %s" % self._dataCollectionId.__class__.__name__ + raise BaseException(strMessage) + if dirN is None: + self._dirN = None + elif dirN.__class__.__name__ == "XSDataFile": + self._dirN = dirN + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'dirN' is not XSDataFile but %s" % self._dirN.__class__.__name__ + raise BaseException(strMessage) + if templateN is None: + self._templateN = None + elif templateN.__class__.__name__ == "XSDataString": + self._templateN = templateN + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'templateN' is not XSDataString but %s" % self._templateN.__class__.__name__ + raise BaseException(strMessage) + if fromN is None: + self._fromN = None + elif fromN.__class__.__name__ == "XSDataInteger": + self._fromN = fromN + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'fromN' is not XSDataInteger but %s" % self._fromN.__class__.__name__ + raise BaseException(strMessage) + if toN is None: + self._toN = None + elif toN.__class__.__name__ == "XSDataInteger": + self._toN = toN + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'toN' is not XSDataInteger but %s" % self._toN.__class__.__name__ + raise BaseException(strMessage) + if processDirectory is None: + self._processDirectory = None + elif processDirectory.__class__.__name__ == "XSDataFile": + self._processDirectory = processDirectory + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'processDirectory' is not XSDataFile but %s" % self._processDirectory.__class__.__name__ + raise BaseException(strMessage) + if doAnom is None: + self._doAnom = None + elif doAnom.__class__.__name__ == "XSDataBoolean": + self._doAnom = doAnom + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'doAnom' is not XSDataBoolean but %s" % self._doAnom.__class__.__name__ + raise BaseException(strMessage) + if doAnomAndNonanom is None: + self._doAnomAndNonanom = None + elif doAnomAndNonanom.__class__.__name__ == "XSDataBoolean": + self._doAnomAndNonanom = doAnomAndNonanom + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'doAnomAndNonanom' is not XSDataBoolean but %s" % self._doAnomAndNonanom.__class__.__name__ + raise BaseException(strMessage) + if symm is None: + self._symm = None + elif symm.__class__.__name__ == "XSDataString": + self._symm = symm + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'symm' is not XSDataString but %s" % self._symm.__class__.__name__ + raise BaseException(strMessage) + if cell is None: + self._cell = None + elif cell.__class__.__name__ == "XSDataString": + self._cell = cell + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'cell' is not XSDataString but %s" % self._cell.__class__.__name__ + raise BaseException(strMessage) + if reprocess is None: + self._reprocess = None + elif reprocess.__class__.__name__ == "XSDataBoolean": + self._reprocess = reprocess + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'reprocess' is not XSDataBoolean but %s" % self._reprocess.__class__.__name__ + raise BaseException(strMessage) + if lowResolutionLimit is None: + self._lowResolutionLimit = None + elif lowResolutionLimit.__class__.__name__ == "XSDataDouble": + self._lowResolutionLimit = lowResolutionLimit + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'lowResolutionLimit' is not XSDataDouble but %s" % self._lowResolutionLimit.__class__.__name__ + raise BaseException(strMessage) + if highResolutionLimit is None: + self._highResolutionLimit = None + elif highResolutionLimit.__class__.__name__ == "XSDataDouble": + self._highResolutionLimit = highResolutionLimit + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'highResolutionLimit' is not XSDataDouble but %s" % self._highResolutionLimit.__class__.__name__ + raise BaseException(strMessage) + if configDef is None: + self._configDef = None + elif configDef.__class__.__name__ == "XSDataFile": + self._configDef = configDef + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'configDef' is not XSDataFile but %s" % self._configDef.__class__.__name__ + raise BaseException(strMessage) + + # Methods and properties for the 'dataCollectionId' attribute + def getDataCollectionId(self): return self._dataCollectionId + def setDataCollectionId(self, dataCollectionId): + if dataCollectionId is None: + self._dataCollectionId = None + elif dataCollectionId.__class__.__name__ == "XSDataInteger": + self._dataCollectionId = dataCollectionId + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setDataCollectionId argument is not XSDataInteger but %s" % dataCollectionId.__class__.__name__ + raise BaseException(strMessage) + def delDataCollectionId(self): self._dataCollectionId = None + dataCollectionId = property(getDataCollectionId, setDataCollectionId, delDataCollectionId, "Property for dataCollectionId") + # Methods and properties for the 'dirN' attribute + def getDirN(self): return self._dirN + def setDirN(self, dirN): + if dirN is None: + self._dirN = None + elif dirN.__class__.__name__ == "XSDataFile": + self._dirN = dirN + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setDirN argument is not XSDataFile but %s" % dirN.__class__.__name__ + raise BaseException(strMessage) + def delDirN(self): self._dirN = None + dirN = property(getDirN, setDirN, delDirN, "Property for dirN") + # Methods and properties for the 'templateN' attribute + def getTemplateN(self): return self._templateN + def setTemplateN(self, templateN): + if templateN is None: + self._templateN = None + elif templateN.__class__.__name__ == "XSDataString": + self._templateN = templateN + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setTemplateN argument is not XSDataString but %s" % templateN.__class__.__name__ + raise BaseException(strMessage) + def delTemplateN(self): self._templateN = None + templateN = property(getTemplateN, setTemplateN, delTemplateN, "Property for templateN") + # Methods and properties for the 'fromN' attribute + def getFromN(self): return self._fromN + def setFromN(self, fromN): + if fromN is None: + self._fromN = None + elif fromN.__class__.__name__ == "XSDataInteger": + self._fromN = fromN + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setFromN argument is not XSDataInteger but %s" % fromN.__class__.__name__ + raise BaseException(strMessage) + def delFromN(self): self._fromN = None + fromN = property(getFromN, setFromN, delFromN, "Property for fromN") + # Methods and properties for the 'toN' attribute + def getToN(self): return self._toN + def setToN(self, toN): + if toN is None: + self._toN = None + elif toN.__class__.__name__ == "XSDataInteger": + self._toN = toN + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setToN argument is not XSDataInteger but %s" % toN.__class__.__name__ + raise BaseException(strMessage) + def delToN(self): self._toN = None + toN = property(getToN, setToN, delToN, "Property for toN") + # Methods and properties for the 'processDirectory' attribute + def getProcessDirectory(self): return self._processDirectory + def setProcessDirectory(self, processDirectory): + if processDirectory is None: + self._processDirectory = None + elif processDirectory.__class__.__name__ == "XSDataFile": + self._processDirectory = processDirectory + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setProcessDirectory argument is not XSDataFile but %s" % processDirectory.__class__.__name__ + raise BaseException(strMessage) + def delProcessDirectory(self): self._processDirectory = None + processDirectory = property(getProcessDirectory, setProcessDirectory, delProcessDirectory, "Property for processDirectory") + # Methods and properties for the 'doAnom' attribute + def getDoAnom(self): return self._doAnom + def setDoAnom(self, doAnom): + if doAnom is None: + self._doAnom = None + elif doAnom.__class__.__name__ == "XSDataBoolean": + self._doAnom = doAnom + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setDoAnom argument is not XSDataBoolean but %s" % doAnom.__class__.__name__ + raise BaseException(strMessage) + def delDoAnom(self): self._doAnom = None + doAnom = property(getDoAnom, setDoAnom, delDoAnom, "Property for doAnom") + # Methods and properties for the 'doAnomAndNonanom' attribute + def getDoAnomAndNonanom(self): return self._doAnomAndNonanom + def setDoAnomAndNonanom(self, doAnomAndNonanom): + if doAnomAndNonanom is None: + self._doAnomAndNonanom = None + elif doAnomAndNonanom.__class__.__name__ == "XSDataBoolean": + self._doAnomAndNonanom = doAnomAndNonanom + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setDoAnomAndNonanom argument is not XSDataBoolean but %s" % doAnomAndNonanom.__class__.__name__ + raise BaseException(strMessage) + def delDoAnomAndNonanom(self): self._doAnomAndNonanom = None + doAnomAndNonanom = property(getDoAnomAndNonanom, setDoAnomAndNonanom, delDoAnomAndNonanom, "Property for doAnomAndNonanom") + # Methods and properties for the 'symm' attribute + def getSymm(self): return self._symm + def setSymm(self, symm): + if symm is None: + self._symm = None + elif symm.__class__.__name__ == "XSDataString": + self._symm = symm + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setSymm argument is not XSDataString but %s" % symm.__class__.__name__ + raise BaseException(strMessage) + def delSymm(self): self._symm = None + symm = property(getSymm, setSymm, delSymm, "Property for symm") + setSpacegroup = setSymm + getSpacegroup = getSymm + delSpacegroup = delSymm + # Methods and properties for the 'configDef' attribute + def getConfigDef(self): return self._configDef + def setConfigDef(self, configDef): + if configDef is None: + self._configDef = None + elif configDef.__class__.__name__ == "XSDataFile": + self._configDef = configDef + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setDirN argument is not XSDataFile but %s" % configDef.__class__.__name__ + raise BaseException(strMessage) + def delConfigDef(self): self._configDef = None + configDef = property(getConfigDef, setConfigDef, delConfigDef, "Property for configDef") + # Methods and properties for the 'cell' attribute + def getCell(self): return self._cell + def setCell(self, cell): + if cell is None: + self._cell = None + elif cell.__class__.__name__ == "XSDataString": + self._cell = cell + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setCell argument is not XSDataString but %s" % cell.__class__.__name__ + raise BaseException(strMessage) + def delCell(self): self._cell = None + cell = property(getCell, setCell, delCell, "Property for cell") + # Methods and properties for the 'reprocess' attribute + def getReprocess(self): return self._reprocess + def setReprocess(self, reprocess): + if reprocess is None: + self._reprocess = None + elif reprocess.__class__.__name__ == "XSDataBoolean": + self._reprocess = reprocess + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setReprocess argument is not XSDataBoolean but %s" % reprocess.__class__.__name__ + raise BaseException(strMessage) + def delReprocess(self): self._reprocess = None + reprocess = property(getReprocess, setReprocess, delReprocess, "Property for reprocess") + # Methods and properties for the 'lowResolutionLimit' attribute + def getLowResolutionLimit(self): return self._lowResolutionLimit + def setLowResolutionLimit(self, lowResolutionLimit): + if lowResolutionLimit is None: + self._lowResolutionLimit = None + elif lowResolutionLimit.__class__.__name__ == "XSDataDouble": + self._lowResolutionLimit = lowResolutionLimit + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setLowResolutionLimit argument is not XSDataDouble but %s" % lowResolutionLimit.__class__.__name__ + raise BaseException(strMessage) + def delLowResolutionLimit(self): self._lowResolutionLimit = None + lowResolutionLimit = property(getLowResolutionLimit, setLowResolutionLimit, delLowResolutionLimit, "Property for lowResolutionLimit") + # Methods and properties for the 'highResolutionLimit' attribute + def getHighResolutionLimit(self): return self._highResolutionLimit + def setHighResolutionLimit(self, highResolutionLimit): + if highResolutionLimit is None: + self._highResolutionLimit = None + elif highResolutionLimit.__class__.__name__ == "XSDataDouble": + self._highResolutionLimit = highResolutionLimit + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.setHighResolutionLimit argument is not XSDataDouble but %s" % highResolutionLimit.__class__.__name__ + raise BaseException(strMessage) + def delHighResolutionLimit(self): self._highResolutionLimit = None + highResolutionLimit = property(getHighResolutionLimit, setHighResolutionLimit, delHighResolutionLimit, "Property for highResolutionLimit") + def export(self, outfile, level, name_='XSDataInputControlAutoPROC'): + showIndent(outfile, level) + outfile.write(unicode('<%s>\n' % name_)) + self.exportChildren(outfile, level + 1, name_) + showIndent(outfile, level) + outfile.write(unicode('\n' % name_)) + def exportChildren(self, outfile, level, name_='XSDataInputControlAutoPROC'): + XSDataInput.exportChildren(self, outfile, level, name_) + if self._dataCollectionId is not None: + self.dataCollectionId.export(outfile, level, name_='dataCollectionId') + if self._dirN is not None: + self.dirN.export(outfile, level, name_='dirN') + if self._configDef is not None: + self.configDef.export(outfile, level, name_='configDef') + if self._templateN is not None: + self.templateN.export(outfile, level, name_='templateN') + if self._fromN is not None: + self.fromN.export(outfile, level, name_='fromN') + if self._toN is not None: + self.toN.export(outfile, level, name_='toN') + if self._processDirectory is not None: + self.processDirectory.export(outfile, level, name_='processDirectory') + if self._doAnom is not None: + self.doAnom.export(outfile, level, name_='doAnom') + if self._doAnomAndNonanom is not None: + self.doAnomAndNonanom.export(outfile, level, name_='doAnomAndNonanom') + if self._symm is not None: + self.symm.export(outfile, level, name_='symm') + if self._cell is not None: + self.cell.export(outfile, level, name_='cell') + if self._reprocess is not None: + self.reprocess.export(outfile, level, name_='reprocess') + if self._lowResolutionLimit is not None: + self.lowResolutionLimit.export(outfile, level, name_='lowResolutionLimit') + if self._highResolutionLimit is not None: + self.highResolutionLimit.export(outfile, level, name_='highResolutionLimit') + def build(self, node_): + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'dataCollectionId': + obj_ = XSDataInteger() + obj_.build(child_) + self.setDataCollectionId(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'dirN': + obj_ = XSDataFile() + obj_.build(child_) + self.setDirN(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'configDef': + obj_ = XSDataFile() + obj_.build(child_) + self.setConfigDef(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'templateN': + obj_ = XSDataString() + obj_.build(child_) + self.setTemplateN(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'fromN': + obj_ = XSDataInteger() + obj_.build(child_) + self.setFromN(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'toN': + obj_ = XSDataInteger() + obj_.build(child_) + self.setToN(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'processDirectory': + obj_ = XSDataFile() + obj_.build(child_) + self.setProcessDirectory(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'doAnom': + obj_ = XSDataBoolean() + obj_.build(child_) + self.setDoAnom(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'doAnomAndNonanom': + obj_ = XSDataBoolean() + obj_.build(child_) + self.setDoAnomAndNonanom(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'symm': + obj_ = XSDataString() + obj_.build(child_) + self.setSymm(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'cell': + obj_ = XSDataString() + obj_.build(child_) + self.setCell(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'reprocess': + obj_ = XSDataBoolean() + obj_.build(child_) + self.setReprocess(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'lowResolutionLimit': + obj_ = XSDataDouble() + obj_.build(child_) + self.setLowResolutionLimit(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'highResolutionLimit': + obj_ = XSDataDouble() + obj_.build(child_) + self.setHighResolutionLimit(obj_) + XSDataInput.buildChildren(self, child_, nodeName_) + #Method for marshalling an object + def marshal( self ): + oStreamString = StringIO() + oStreamString.write(unicode('\n')) + self.export( oStreamString, 0, name_="XSDataInputControlAutoPROC" ) + oStringXML = oStreamString.getvalue() + oStreamString.close() + return oStringXML + #Only to export the entire XML tree to a file stream on disk + def exportToFile( self, _outfileName ): + outfile = open( _outfileName, "w" ) + outfile.write(unicode('\n')) + self.export( outfile, 0, name_='XSDataInputControlAutoPROC' ) + outfile.close() + #Deprecated method, replaced by exportToFile + def outputFile( self, _outfileName ): + print("WARNING: Method outputFile in class XSDataInputControlAutoPROC is deprecated, please use instead exportToFile!") + self.exportToFile(_outfileName) + #Method for making a copy in a new instance + def copy( self ): + return XSDataInputControlAutoPROC.parseString(self.marshal()) + #Static method for parsing a string + def parseString( _inString ): + doc = minidom.parseString(_inString) + rootNode = doc.documentElement + rootObj = XSDataInputControlAutoPROC() + rootObj.build(rootNode) + # Check that all minOccurs are obeyed by marshalling the created object + oStreamString = StringIO() + rootObj.export( oStreamString, 0, name_="XSDataInputControlAutoPROC" ) + oStreamString.close() + return rootObj + parseString = staticmethod( parseString ) + #Static method for parsing a file + def parseFile( _inFilePath ): + doc = minidom.parse(_inFilePath) + rootNode = doc.documentElement + rootObj = XSDataInputControlAutoPROC() + rootObj.build(rootNode) + return rootObj + parseFile = staticmethod( parseFile ) +# end class XSDataInputControlAutoPROC + + +class XSDataResultControlAutoPROC(XSDataResult): + def __init__(self, status=None): + XSDataResult.__init__(self, status) + def export(self, outfile, level, name_='XSDataResultControlAutoPROC'): + showIndent(outfile, level) + outfile.write(unicode('<%s>\n' % name_)) + self.exportChildren(outfile, level + 1, name_) + showIndent(outfile, level) + outfile.write(unicode('\n' % name_)) + def exportChildren(self, outfile, level, name_='XSDataResultControlAutoPROC'): + XSDataResult.exportChildren(self, outfile, level, name_) + def build(self, node_): + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildChildren(self, child_, nodeName_): + pass + XSDataResult.buildChildren(self, child_, nodeName_) + #Method for marshalling an object + def marshal( self ): + oStreamString = StringIO() + oStreamString.write(unicode('\n')) + self.export( oStreamString, 0, name_="XSDataResultControlAutoPROC" ) + oStringXML = oStreamString.getvalue() + oStreamString.close() + return oStringXML + #Only to export the entire XML tree to a file stream on disk + def exportToFile( self, _outfileName ): + outfile = open( _outfileName, "w" ) + outfile.write(unicode('\n')) + self.export( outfile, 0, name_='XSDataResultControlAutoPROC' ) + outfile.close() + #Deprecated method, replaced by exportToFile + def outputFile( self, _outfileName ): + print("WARNING: Method outputFile in class XSDataResultControlAutoPROC is deprecated, please use instead exportToFile!") + self.exportToFile(_outfileName) + #Method for making a copy in a new instance + def copy( self ): + return XSDataResultControlAutoPROC.parseString(self.marshal()) + #Static method for parsing a string + def parseString( _inString ): + doc = minidom.parseString(_inString) + rootNode = doc.documentElement + rootObj = XSDataResultControlAutoPROC() + rootObj.build(rootNode) + # Check that all minOccurs are obeyed by marshalling the created object + oStreamString = StringIO() + rootObj.export( oStreamString, 0, name_="XSDataResultControlAutoPROC" ) + oStreamString.close() + return rootObj + parseString = staticmethod( parseString ) + #Static method for parsing a file + def parseFile( _inFilePath ): + doc = minidom.parse(_inFilePath) + rootNode = doc.documentElement + rootObj = XSDataResultControlAutoPROC() + rootObj.build(rootNode) + return rootObj + parseFile = staticmethod( parseFile ) +# end class XSDataResultControlAutoPROC + + +class XSDataInputControlDimpleAP(XSDataInput): + def __init__(self, configuration=None, resultsDirectory=None, autoProcProgramId=None, pdbDirectory=None, beamline=None, sessionDate=None, proposal=None, imagePrefix=None, pyarchPath=None, mtzFile=None, dataCollectionId=None): + XSDataInput.__init__(self, configuration) + if dataCollectionId is None: + self._dataCollectionId = None + elif dataCollectionId.__class__.__name__ == "XSDataInteger": + self._dataCollectionId = dataCollectionId + else: + strMessage = "ERROR! XSDataInputControlDimpleAP constructor argument 'dataCollectionId' is not XSDataInteger but %s" % self._dataCollectionId.__class__.__name__ + raise BaseException(strMessage) + if mtzFile is None: + self._mtzFile = None + elif mtzFile.__class__.__name__ == "XSDataFile": + self._mtzFile = mtzFile + else: + strMessage = "ERROR! XSDataInputControlDimpleAP constructor argument 'mtzFile' is not XSDataFile but %s" % self._mtzFile.__class__.__name__ + raise BaseException(strMessage) + if pyarchPath is None: + self._pyarchPath = None + elif pyarchPath.__class__.__name__ == "XSDataFile": + self._pyarchPath = pyarchPath + else: + strMessage = "ERROR! XSDataInputControlDimpleAP constructor argument 'pyarchPath' is not XSDataFile but %s" % self._pyarchPath.__class__.__name__ + raise BaseException(strMessage) + if imagePrefix is None: + self._imagePrefix = None + elif imagePrefix.__class__.__name__ == "XSDataString": + self._imagePrefix = imagePrefix + else: + strMessage = "ERROR! XSDataInputControlDimpleAP constructor argument 'imagePrefix' is not XSDataString but %s" % self._imagePrefix.__class__.__name__ + raise BaseException(strMessage) + if proposal is None: + self._proposal = None + elif proposal.__class__.__name__ == "XSDataString": + self._proposal = proposal + else: + strMessage = "ERROR! XSDataInputControlDimpleAP constructor argument 'proposal' is not XSDataString but %s" % self._proposal.__class__.__name__ + raise BaseException(strMessage) + if sessionDate is None: + self._sessionDate = None + elif sessionDate.__class__.__name__ == "XSDataString": + self._sessionDate = sessionDate + else: + strMessage = "ERROR! XSDataInputControlDimpleAP constructor argument 'sessionDate' is not XSDataString but %s" % self._sessionDate.__class__.__name__ + raise BaseException(strMessage) + if beamline is None: + self._beamline = None + elif beamline.__class__.__name__ == "XSDataString": + self._beamline = beamline + else: + strMessage = "ERROR! XSDataInputControlDimpleAP constructor argument 'beamline' is not XSDataString but %s" % self._beamline.__class__.__name__ + raise BaseException(strMessage) + if pdbDirectory is None: + self._pdbDirectory = None + elif pdbDirectory.__class__.__name__ == "XSDataFile": + self._pdbDirectory = pdbDirectory + else: + strMessage = "ERROR! XSDataInputControlDimpleAP constructor argument 'pdbDirectory' is not XSDataFile but %s" % self._pdbDirectory.__class__.__name__ + raise BaseException(strMessage) + if autoProcProgramId is None: + self._autoProcProgramId = None + elif autoProcProgramId.__class__.__name__ == "XSDataInteger": + self._autoProcProgramId = autoProcProgramId + else: + strMessage = "ERROR! XSDataInputControlDimpleAP constructor argument 'autoProcProgramId' is not XSDataInteger but %s" % self._autoProcProgramId.__class__.__name__ + raise BaseException(strMessage) + if resultsDirectory is None: + self._resultsDirectory = None + elif resultsDirectory.__class__.__name__ == "XSDataFile": + self._resultsDirectory = resultsDirectory + else: + strMessage = "ERROR! XSDataInputControlDimpleAP constructor argument 'resultsDirectory' is not XSDataFile but %s" % self._resultsDirectory.__class__.__name__ + raise BaseException(strMessage) + # Methods and properties for the 'dataCollectionId' attribute + def getDataCollectionId(self): return self._dataCollectionId + def setDataCollectionId(self, dataCollectionId): + if dataCollectionId is None: + self._dataCollectionId = None + elif dataCollectionId.__class__.__name__ == "XSDataInteger": + self._dataCollectionId = dataCollectionId + else: + strMessage = "ERROR! XSDataInputControlDimpleAP.setDataCollectionId argument is not XSDataInteger but %s" % dataCollectionId.__class__.__name__ + raise BaseException(strMessage) + def delDataCollectionId(self): self._dataCollectionId = None + dataCollectionId = property(getDataCollectionId, setDataCollectionId, delDataCollectionId, "Property for dataCollectionId") + # Methods and properties for the 'mtzFile' attribute + def getMtzFile(self): return self._mtzFile + def setMtzFile(self, mtzFile): + if mtzFile is None: + self._mtzFile = None + elif mtzFile.__class__.__name__ == "XSDataFile": + self._mtzFile = mtzFile + else: + strMessage = "ERROR! XSDataInputControlDimpleAP.setMtzFile argument is not XSDataFile but %s" % mtzFile.__class__.__name__ + raise BaseException(strMessage) + def delMtzFile(self): self._mtzFile = None + mtzFile = property(getMtzFile, setMtzFile, delMtzFile, "Property for mtzFile") + # Methods and properties for the 'pyarchPath' attribute + def getPyarchPath(self): return self._pyarchPath + def setPyarchPath(self, pyarchPath): + if pyarchPath is None: + self._pyarchPath = None + elif pyarchPath.__class__.__name__ == "XSDataFile": + self._pyarchPath = pyarchPath + else: + strMessage = "ERROR! XSDataInputControlDimpleAP.setPyarchPath argument is not XSDataFile but %s" % pyarchPath.__class__.__name__ + raise BaseException(strMessage) + def delPyarchPath(self): self._pyarchPath = None + pyarchPath = property(getPyarchPath, setPyarchPath, delPyarchPath, "Property for pyarchPath") + # Methods and properties for the 'imagePrefix' attribute + def getImagePrefix(self): return self._imagePrefix + def setImagePrefix(self, imagePrefix): + if imagePrefix is None: + self._imagePrefix = None + elif imagePrefix.__class__.__name__ == "XSDataString": + self._imagePrefix = imagePrefix + else: + strMessage = "ERROR! XSDataInputControlDimpleAP.setImagePrefix argument is not XSDataString but %s" % imagePrefix.__class__.__name__ + raise BaseException(strMessage) + def delImagePrefix(self): self._imagePrefix = None + imagePrefix = property(getImagePrefix, setImagePrefix, delImagePrefix, "Property for imagePrefix") + # Methods and properties for the 'proposal' attribute + def getProposal(self): return self._proposal + def setProposal(self, proposal): + if proposal is None: + self._proposal = None + elif proposal.__class__.__name__ == "XSDataString": + self._proposal = proposal + else: + strMessage = "ERROR! XSDataInputControlDimpleAP.setProposal argument is not XSDataString but %s" % proposal.__class__.__name__ + raise BaseException(strMessage) + def delProposal(self): self._proposal = None + proposal = property(getProposal, setProposal, delProposal, "Property for proposal") + # Methods and properties for the 'sessionDate' attribute + def getSessionDate(self): return self._sessionDate + def setSessionDate(self, sessionDate): + if sessionDate is None: + self._sessionDate = None + elif sessionDate.__class__.__name__ == "XSDataString": + self._sessionDate = sessionDate + else: + strMessage = "ERROR! XSDataInputControlDimpleAP.setSessionDate argument is not XSDataString but %s" % sessionDate.__class__.__name__ + raise BaseException(strMessage) + def delSessionDate(self): self._sessionDate = None + sessionDate = property(getSessionDate, setSessionDate, delSessionDate, "Property for sessionDate") + # Methods and properties for the 'beamline' attribute + def getBeamline(self): return self._beamline + def setBeamline(self, beamline): + if beamline is None: + self._beamline = None + elif beamline.__class__.__name__ == "XSDataString": + self._beamline = beamline + else: + strMessage = "ERROR! XSDataInputControlDimpleAP.setBeamline argument is not XSDataString but %s" % beamline.__class__.__name__ + raise BaseException(strMessage) + def delBeamline(self): self._beamline = None + beamline = property(getBeamline, setBeamline, delBeamline, "Property for beamline") + # Methods and properties for the 'pdbDirectory' attribute + def getPdbDirectory(self): return self._pdbDirectory + def setPdbDirectory(self, pdbDirectory): + if pdbDirectory is None: + self._pdbDirectory = None + elif pdbDirectory.__class__.__name__ == "XSDataFile": + self._pdbDirectory = pdbDirectory + else: + strMessage = "ERROR! XSDataInputControlDimpleAP.setPdbDirectory argument is not XSDataFile but %s" % pdbDirectory.__class__.__name__ + raise BaseException(strMessage) + def delPdbDirectory(self): self._pdbDirectory = None + pdbDirectory = property(getPdbDirectory, setPdbDirectory, delPdbDirectory, "Property for pdbDirectory") + # Methods and properties for the 'autoProcProgramId' attribute + def getAutoProcProgramId(self): return self._autoProcProgramId + def setAutoProcProgramId(self, autoProcProgramId): + if autoProcProgramId is None: + self._autoProcProgramId = None + elif autoProcProgramId.__class__.__name__ == "XSDataInteger": + self._autoProcProgramId = autoProcProgramId + else: + strMessage = "ERROR! XSDataInputControlDimpleAP.setAutoProcProgramId argument is not XSDataInteger but %s" % autoProcProgramId.__class__.__name__ + raise BaseException(strMessage) + def delAutoProcProgramId(self): self._autoProcProgramId = None + autoProcProgramId = property(getAutoProcProgramId, setAutoProcProgramId, delAutoProcProgramId, "Property for autoProcProgramId") + # Methods and properties for the 'resultsDirectory' attribute + def getResultsDirectory(self): return self._resultsDirectory + def setResultsDirectory(self, resultsDirectory): + if resultsDirectory is None: + self._resultsDirectory = None + elif resultsDirectory.__class__.__name__ == "XSDataFile": + self._resultsDirectory = resultsDirectory + else: + strMessage = "ERROR! XSDataInputControlDimpleAP.setResultsDirectory argument is not XSDataFile but %s" % resultsDirectory.__class__.__name__ + raise BaseException(strMessage) + def delResultsDirectory(self): self._resultsDirectory = None + resultsDirectory = property(getResultsDirectory, setResultsDirectory, delResultsDirectory, "Property for resultsDirectory") + def export(self, outfile, level, name_='XSDataInputControlDimpleAP'): + showIndent(outfile, level) + outfile.write(unicode('<%s>\n' % name_)) + self.exportChildren(outfile, level + 1, name_) + showIndent(outfile, level) + outfile.write(unicode('\n' % name_)) + def exportChildren(self, outfile, level, name_='XSDataInputControlDimpleAP'): + XSDataInput.exportChildren(self, outfile, level, name_) + if self._dataCollectionId is not None: + self.dataCollectionId.export(outfile, level, name_='dataCollectionId') + else: + warnEmptyAttribute("dataCollectionId", "XSDataInteger") + if self._mtzFile is not None: + self.mtzFile.export(outfile, level, name_='mtzFile') + else: + warnEmptyAttribute("mtzFile", "XSDataFile") + if self._pyarchPath is not None: + self.pyarchPath.export(outfile, level, name_='pyarchPath') + else: + warnEmptyAttribute("pyarchPath", "XSDataFile") + if self._imagePrefix is not None: + self.imagePrefix.export(outfile, level, name_='imagePrefix') + else: + warnEmptyAttribute("imagePrefix", "XSDataString") + if self._proposal is not None: + self.proposal.export(outfile, level, name_='proposal') + else: + warnEmptyAttribute("proposal", "XSDataString") + if self._sessionDate is not None: + self.sessionDate.export(outfile, level, name_='sessionDate') + else: + warnEmptyAttribute("sessionDate", "XSDataString") + if self._beamline is not None: + self.beamline.export(outfile, level, name_='beamline') + else: + warnEmptyAttribute("beamline", "XSDataString") + if self._pdbDirectory is not None: + self.pdbDirectory.export(outfile, level, name_='pdbDirectory') + if self._autoProcProgramId is not None: + self.autoProcProgramId.export(outfile, level, name_='autoProcProgramId') + if self._resultsDirectory is not None: + self.resultsDirectory.export(outfile, level, name_='resultsDirectory') + def build(self, node_): + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'dataCollectionId': + obj_ = XSDataInteger() + obj_.build(child_) + self.setDataCollectionId(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'mtzFile': + obj_ = XSDataFile() + obj_.build(child_) + self.setMtzFile(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'pyarchPath': + obj_ = XSDataFile() + obj_.build(child_) + self.setPyarchPath(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'imagePrefix': + obj_ = XSDataString() + obj_.build(child_) + self.setImagePrefix(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'proposal': + obj_ = XSDataString() + obj_.build(child_) + self.setProposal(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'sessionDate': + obj_ = XSDataString() + obj_.build(child_) + self.setSessionDate(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'beamline': + obj_ = XSDataString() + obj_.build(child_) + self.setBeamline(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'pdbDirectory': + obj_ = XSDataFile() + obj_.build(child_) + self.setPdbDirectory(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'autoProcProgramId': + obj_ = XSDataInteger() + obj_.build(child_) + self.setAutoProcProgramId(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'resultsDirectory': + obj_ = XSDataFile() + obj_.build(child_) + self.setResultsDirectory(obj_) + XSDataInput.buildChildren(self, child_, nodeName_) + #Method for marshalling an object + def marshal( self ): + oStreamString = StringIO() + oStreamString.write(unicode('\n')) + self.export( oStreamString, 0, name_="XSDataInputControlDimpleAP" ) + oStringXML = oStreamString.getvalue() + oStreamString.close() + return oStringXML + #Only to export the entire XML tree to a file stream on disk + def exportToFile( self, _outfileName ): + outfile = open( _outfileName, "w" ) + outfile.write(unicode('\n')) + self.export( outfile, 0, name_='XSDataInputControlDimpleAP' ) + outfile.close() + #Deprecated method, replaced by exportToFile + def outputFile( self, _outfileName ): + print("WARNING: Method outputFile in class XSDataInputControlDimpleAP is deprecated, please use instead exportToFile!") + self.exportToFile(_outfileName) + #Method for making a copy in a new instance + def copy( self ): + return XSDataInputControlDimpleAP.parseString(self.marshal()) + #Static method for parsing a string + def parseString( _inString ): + doc = minidom.parseString(_inString) + rootNode = doc.documentElement + rootObj = XSDataInputControlDimpleAP() + rootObj.build(rootNode) + # Check that all minOccurs are obeyed by marshalling the created object + oStreamString = StringIO() + rootObj.export( oStreamString, 0, name_="XSDataInputControlDimpleAP" ) + oStreamString.close() + return rootObj + parseString = staticmethod( parseString ) + #Static method for parsing a file + def parseFile( _inFilePath ): + doc = minidom.parse(_inFilePath) + rootNode = doc.documentElement + rootObj = XSDataInputControlDimpleAP() + rootObj.build(rootNode) + return rootObj + parseFile = staticmethod( parseFile ) +# end class XSDataInputControlDimpleAP + + +class XSDataResultControlDimpleAP(XSDataResult): + def __init__(self, status=None, dimpleExecutedSuccessfully=None): + XSDataResult.__init__(self, status) + if dimpleExecutedSuccessfully is None: + self._dimpleExecutedSuccessfully = None + elif dimpleExecutedSuccessfully.__class__.__name__ == "XSDataBoolean": + self._dimpleExecutedSuccessfully = dimpleExecutedSuccessfully + else: + strMessage = "ERROR! XSDataResultControlDimpleAP constructor argument 'dimpleExecutedSuccessfully' is not XSDataBoolean but %s" % self._dimpleExecutedSuccessfully.__class__.__name__ + raise BaseException(strMessage) + # Methods and properties for the 'dimpleExecutedSuccessfully' attribute + def getDimpleExecutedSuccessfully(self): return self._dimpleExecutedSuccessfully + def setDimpleExecutedSuccessfully(self, dimpleExecutedSuccessfully): + if dimpleExecutedSuccessfully is None: + self._dimpleExecutedSuccessfully = None + elif dimpleExecutedSuccessfully.__class__.__name__ == "XSDataBoolean": + self._dimpleExecutedSuccessfully = dimpleExecutedSuccessfully + else: + strMessage = "ERROR! XSDataResultControlDimpleAP.setDimpleExecutedSuccessfully argument is not XSDataBoolean but %s" % dimpleExecutedSuccessfully.__class__.__name__ + raise BaseException(strMessage) + def delDimpleExecutedSuccessfully(self): self._dimpleExecutedSuccessfully = None + dimpleExecutedSuccessfully = property(getDimpleExecutedSuccessfully, setDimpleExecutedSuccessfully, delDimpleExecutedSuccessfully, "Property for dimpleExecutedSuccessfully") + def export(self, outfile, level, name_='XSDataResultControlDimpleAP'): + showIndent(outfile, level) + outfile.write(unicode('<%s>\n' % name_)) + self.exportChildren(outfile, level + 1, name_) + showIndent(outfile, level) + outfile.write(unicode('\n' % name_)) + def exportChildren(self, outfile, level, name_='XSDataResultControlDimpleAP'): + XSDataResult.exportChildren(self, outfile, level, name_) + if self._dimpleExecutedSuccessfully is not None: + self.dimpleExecutedSuccessfully.export(outfile, level, name_='dimpleExecutedSuccessfully') + else: + warnEmptyAttribute("dimpleExecutedSuccessfully", "XSDataBoolean") + def build(self, node_): + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'dimpleExecutedSuccessfully': + obj_ = XSDataBoolean() + obj_.build(child_) + self.setDimpleExecutedSuccessfully(obj_) + XSDataResult.buildChildren(self, child_, nodeName_) + #Method for marshalling an object + def marshal( self ): + oStreamString = StringIO() + oStreamString.write(unicode('\n')) + self.export( oStreamString, 0, name_="XSDataResultControlDimpleAP" ) + oStringXML = oStreamString.getvalue() + oStreamString.close() + return oStringXML + #Only to export the entire XML tree to a file stream on disk + def exportToFile( self, _outfileName ): + outfile = open( _outfileName, "w" ) + outfile.write(unicode('\n')) + self.export( outfile, 0, name_='XSDataResultControlDimpleAP' ) + outfile.close() + #Deprecated method, replaced by exportToFile + def outputFile( self, _outfileName ): + print("WARNING: Method outputFile in class XSDataResultControlDimpleAP is deprecated, please use instead exportToFile!") + self.exportToFile(_outfileName) + #Method for making a copy in a new instance + def copy( self ): + return XSDataResultControlDimpleAP.parseString(self.marshal()) + #Static method for parsing a string + def parseString( _inString ): + doc = minidom.parseString(_inString) + rootNode = doc.documentElement + rootObj = XSDataResultControlDimpleAP() + rootObj.build(rootNode) + # Check that all minOccurs are obeyed by marshalling the created object + oStreamString = StringIO() + rootObj.export( oStreamString, 0, name_="XSDataResultControlDimpleAP" ) + oStreamString.close() + return rootObj + parseString = staticmethod( parseString ) + #Static method for parsing a file + def parseFile( _inFilePath ): + doc = minidom.parse(_inFilePath) + rootNode = doc.documentElement + rootObj = XSDataResultControlDimpleAP() + rootObj.build(rootNode) + return rootObj + parseFile = staticmethod( parseFile ) +# end class XSDataResultControlDimpleAP + +# End of data representation classes. + + diff --git a/mxcubecore/HardwareObjects/ALBA/XalocXSDataControlDozorv1_0.py b/mxcubecore/HardwareObjects/ALBA/XalocXSDataControlDozorv1_0.py new file mode 100644 index 0000000000..209475004a --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocXSDataControlDozorv1_0.py @@ -0,0 +1,1741 @@ +#!/usr/bin/env python + +# +# Generated Thu Jan 12 03:59::59 2017 by EDGenerateDS. +# + +import os, sys +from xml.dom import minidom +from xml.dom import Node + + +strEdnaHome = os.environ.get("EDNA_HOME", None) + +dictLocation = { \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ +} + +try: + from XSDataCommon import XSDataBoolean + from XSDataCommon import XSDataDouble + from XSDataCommon import XSDataFile + from XSDataCommon import XSDataInput + from XSDataCommon import XSDataInteger + from XSDataCommon import XSDataResult + from XSDataCommon import XSDataString + from XSDataCommon import XSDataAngle +except ImportError as error: + if strEdnaHome is not None: + for strXsdName in dictLocation: + strXsdModule = strXsdName + ".py" + strRootdir = os.path.dirname(os.path.abspath(os.path.join(strEdnaHome, dictLocation[strXsdName]))) + for strRoot, listDirs, listFiles in os.walk(strRootdir): + if strXsdModule in listFiles: + sys.path.append(strRoot) + else: + raise error +from XSDataCommon import XSDataBoolean +from XSDataCommon import XSDataDouble +from XSDataCommon import XSDataFile +from XSDataCommon import XSDataInput +from XSDataCommon import XSDataInteger +from XSDataCommon import XSDataResult +from XSDataCommon import XSDataString +from XSDataCommon import XSDataAngle + + + + +# +# Support/utility functions. +# + +# Compabiltity between Python 2 and 3: +if sys.version.startswith('3'): + unicode = str + from io import StringIO +else: + from StringIO import StringIO + + +def showIndent(outfile, level): + for idx in range(level): + outfile.write(unicode(' ')) + + +def warnEmptyAttribute(_strName, _strTypeName): + pass + #if not _strTypeName in ["float", "double", "string", "boolean", "integer"]: + # print("Warning! Non-optional attribute %s of type %s is None!" % (_strName, _strTypeName)) + +class MixedContainer(object): + # Constants for category: + CategoryNone = 0 + CategoryText = 1 + CategorySimple = 2 + CategoryComplex = 3 + # Constants for content_type: + TypeNone = 0 + TypeText = 1 + TypeString = 2 + TypeInteger = 3 + TypeFloat = 4 + TypeDecimal = 5 + TypeDouble = 6 + TypeBoolean = 7 + def __init__(self, category, content_type, name, value): + self.category = category + self.content_type = content_type + self.name = name + self.value = value + def getCategory(self): + return self.category + def getContenttype(self, content_type): + return self.content_type + def getValue(self): + return self.value + def getName(self): + return self.name + def export(self, outfile, level, name): + if self.category == MixedContainer.CategoryText: + outfile.write(self.value) + elif self.category == MixedContainer.CategorySimple: + self.exportSimple(outfile, level, name) + else: # category == MixedContainer.CategoryComplex + self.value.export(outfile, level, name) + def exportSimple(self, outfile, level, name): + if self.content_type == MixedContainer.TypeString: + outfile.write(unicode('<%s>%s' % (self.name, self.value, self.name))) + elif self.content_type == MixedContainer.TypeInteger or \ + self.content_type == MixedContainer.TypeBoolean: + outfile.write(unicode('<%s>%d' % (self.name, self.value, self.name))) + elif self.content_type == MixedContainer.TypeFloat or \ + self.content_type == MixedContainer.TypeDecimal: + outfile.write(unicode('<%s>%f' % (self.name, self.value, self.name))) + elif self.content_type == MixedContainer.TypeDouble: + outfile.write(unicode('<%s>%g' % (self.name, self.value, self.name))) + +# +# Data representation classes. +# + + + +class XSDataControlImageDozor(object): + def __init__(self, angle=None, spotFile=None, visibleResolution=None, spotScore=None, mainScore=None, powderWilsonRfactor=None, powderWilsonCorrelation=None, powderWilsonResolution=None, powderWilsonBfactor=None, powderWilsonScale=None, spotsResolution=None, spotsIntAver=None, spotsNumOf=None, image=None, number=None): + if number is None: + self._number = None + elif number.__class__.__name__ == "XSDataInteger": + self._number = number + else: + strMessage = "ERROR! XSDataControlImageDozor constructor argument 'number' is not XSDataInteger but %s" % self._number.__class__.__name__ + raise BaseException(strMessage) + if image is None: + self._image = None + elif image.__class__.__name__ == "XSDataFile": + self._image = image + else: + strMessage = "ERROR! XSDataControlImageDozor constructor argument 'image' is not XSDataFile but %s" % self._image.__class__.__name__ + raise BaseException(strMessage) + if spotsNumOf is None: + self._spotsNumOf = None + elif spotsNumOf.__class__.__name__ == "XSDataInteger": + self._spotsNumOf = spotsNumOf + else: + strMessage = "ERROR! XSDataControlImageDozor constructor argument 'spotsNumOf' is not XSDataInteger but %s" % self._spotsNumOf.__class__.__name__ + raise BaseException(strMessage) + if spotsIntAver is None: + self._spotsIntAver = None + elif spotsIntAver.__class__.__name__ == "XSDataDouble": + self._spotsIntAver = spotsIntAver + else: + strMessage = "ERROR! XSDataControlImageDozor constructor argument 'spotsIntAver' is not XSDataDouble but %s" % self._spotsIntAver.__class__.__name__ + raise BaseException(strMessage) + if spotsResolution is None: + self._spotsResolution = None + elif spotsResolution.__class__.__name__ == "XSDataDouble": + self._spotsResolution = spotsResolution + else: + strMessage = "ERROR! XSDataControlImageDozor constructor argument 'spotsResolution' is not XSDataDouble but %s" % self._spotsResolution.__class__.__name__ + raise BaseException(strMessage) + if powderWilsonScale is None: + self._powderWilsonScale = None + elif powderWilsonScale.__class__.__name__ == "XSDataDouble": + self._powderWilsonScale = powderWilsonScale + else: + strMessage = "ERROR! XSDataControlImageDozor constructor argument 'powderWilsonScale' is not XSDataDouble but %s" % self._powderWilsonScale.__class__.__name__ + raise BaseException(strMessage) + if powderWilsonBfactor is None: + self._powderWilsonBfactor = None + elif powderWilsonBfactor.__class__.__name__ == "XSDataDouble": + self._powderWilsonBfactor = powderWilsonBfactor + else: + strMessage = "ERROR! XSDataControlImageDozor constructor argument 'powderWilsonBfactor' is not XSDataDouble but %s" % self._powderWilsonBfactor.__class__.__name__ + raise BaseException(strMessage) + if powderWilsonResolution is None: + self._powderWilsonResolution = None + elif powderWilsonResolution.__class__.__name__ == "XSDataDouble": + self._powderWilsonResolution = powderWilsonResolution + else: + strMessage = "ERROR! XSDataControlImageDozor constructor argument 'powderWilsonResolution' is not XSDataDouble but %s" % self._powderWilsonResolution.__class__.__name__ + raise BaseException(strMessage) + if powderWilsonCorrelation is None: + self._powderWilsonCorrelation = None + elif powderWilsonCorrelation.__class__.__name__ == "XSDataDouble": + self._powderWilsonCorrelation = powderWilsonCorrelation + else: + strMessage = "ERROR! XSDataControlImageDozor constructor argument 'powderWilsonCorrelation' is not XSDataDouble but %s" % self._powderWilsonCorrelation.__class__.__name__ + raise BaseException(strMessage) + if powderWilsonRfactor is None: + self._powderWilsonRfactor = None + elif powderWilsonRfactor.__class__.__name__ == "XSDataDouble": + self._powderWilsonRfactor = powderWilsonRfactor + else: + strMessage = "ERROR! XSDataControlImageDozor constructor argument 'powderWilsonRfactor' is not XSDataDouble but %s" % self._powderWilsonRfactor.__class__.__name__ + raise BaseException(strMessage) + if mainScore is None: + self._mainScore = None + elif mainScore.__class__.__name__ == "XSDataDouble": + self._mainScore = mainScore + else: + strMessage = "ERROR! XSDataControlImageDozor constructor argument 'mainScore' is not XSDataDouble but %s" % self._mainScore.__class__.__name__ + raise BaseException(strMessage) + if spotScore is None: + self._spotScore = None + elif spotScore.__class__.__name__ == "XSDataDouble": + self._spotScore = spotScore + else: + strMessage = "ERROR! XSDataControlImageDozor constructor argument 'spotScore' is not XSDataDouble but %s" % self._spotScore.__class__.__name__ + raise BaseException(strMessage) + if visibleResolution is None: + self._visibleResolution = None + elif visibleResolution.__class__.__name__ == "XSDataDouble": + self._visibleResolution = visibleResolution + else: + strMessage = "ERROR! XSDataControlImageDozor constructor argument 'visibleResolution' is not XSDataDouble but %s" % self._visibleResolution.__class__.__name__ + raise BaseException(strMessage) + if spotFile is None: + self._spotFile = None + elif spotFile.__class__.__name__ == "XSDataFile": + self._spotFile = spotFile + else: + strMessage = "ERROR! XSDataControlImageDozor constructor argument 'spotFile' is not XSDataFile but %s" % self._spotFile.__class__.__name__ + raise BaseException(strMessage) + if angle is None: + self._angle = None + elif angle.__class__.__name__ == "XSDataAngle": + self._angle = angle + else: + strMessage = "ERROR! XSDataControlImageDozor constructor argument 'angle' is not XSDataAngle but %s" % self._angle.__class__.__name__ + raise BaseException(strMessage) + # Methods and properties for the 'number' attribute + def getNumber(self): return self._number + def setNumber(self, number): + if number is None: + self._number = None + elif number.__class__.__name__ == "XSDataInteger": + self._number = number + else: + strMessage = "ERROR! XSDataControlImageDozor.setNumber argument is not XSDataInteger but %s" % number.__class__.__name__ + raise BaseException(strMessage) + def delNumber(self): self._number = None + number = property(getNumber, setNumber, delNumber, "Property for number") + # Methods and properties for the 'image' attribute + def getImage(self): return self._image + def setImage(self, image): + if image is None: + self._image = None + elif image.__class__.__name__ == "XSDataFile": + self._image = image + else: + strMessage = "ERROR! XSDataControlImageDozor.setImage argument is not XSDataFile but %s" % image.__class__.__name__ + raise BaseException(strMessage) + def delImage(self): self._image = None + image = property(getImage, setImage, delImage, "Property for image") + # Methods and properties for the 'spotsNumOf' attribute + def getSpotsNumOf(self): return self._spotsNumOf + def setSpotsNumOf(self, spotsNumOf): + if spotsNumOf is None: + self._spotsNumOf = None + elif spotsNumOf.__class__.__name__ == "XSDataInteger": + self._spotsNumOf = spotsNumOf + else: + strMessage = "ERROR! XSDataControlImageDozor.setSpotsNumOf argument is not XSDataInteger but %s" % spotsNumOf.__class__.__name__ + raise BaseException(strMessage) + def delSpotsNumOf(self): self._spotsNumOf = None + spotsNumOf = property(getSpotsNumOf, setSpotsNumOf, delSpotsNumOf, "Property for spotsNumOf") + # Methods and properties for the 'spotsIntAver' attribute + def getSpotsIntAver(self): return self._spotsIntAver + def setSpotsIntAver(self, spotsIntAver): + if spotsIntAver is None: + self._spotsIntAver = None + elif spotsIntAver.__class__.__name__ == "XSDataDouble": + self._spotsIntAver = spotsIntAver + else: + strMessage = "ERROR! XSDataControlImageDozor.setSpotsIntAver argument is not XSDataDouble but %s" % spotsIntAver.__class__.__name__ + raise BaseException(strMessage) + def delSpotsIntAver(self): self._spotsIntAver = None + spotsIntAver = property(getSpotsIntAver, setSpotsIntAver, delSpotsIntAver, "Property for spotsIntAver") + # Methods and properties for the 'spotsResolution' attribute + def getSpotsResolution(self): return self._spotsResolution + def setSpotsResolution(self, spotsResolution): + if spotsResolution is None: + self._spotsResolution = None + elif spotsResolution.__class__.__name__ == "XSDataDouble": + self._spotsResolution = spotsResolution + else: + strMessage = "ERROR! XSDataControlImageDozor.setSpotsResolution argument is not XSDataDouble but %s" % spotsResolution.__class__.__name__ + raise BaseException(strMessage) + def delSpotsResolution(self): self._spotsResolution = None + spotsResolution = property(getSpotsResolution, setSpotsResolution, delSpotsResolution, "Property for spotsResolution") + # Methods and properties for the 'powderWilsonScale' attribute + def getPowderWilsonScale(self): return self._powderWilsonScale + def setPowderWilsonScale(self, powderWilsonScale): + if powderWilsonScale is None: + self._powderWilsonScale = None + elif powderWilsonScale.__class__.__name__ == "XSDataDouble": + self._powderWilsonScale = powderWilsonScale + else: + strMessage = "ERROR! XSDataControlImageDozor.setPowderWilsonScale argument is not XSDataDouble but %s" % powderWilsonScale.__class__.__name__ + raise BaseException(strMessage) + def delPowderWilsonScale(self): self._powderWilsonScale = None + powderWilsonScale = property(getPowderWilsonScale, setPowderWilsonScale, delPowderWilsonScale, "Property for powderWilsonScale") + # Methods and properties for the 'powderWilsonBfactor' attribute + def getPowderWilsonBfactor(self): return self._powderWilsonBfactor + def setPowderWilsonBfactor(self, powderWilsonBfactor): + if powderWilsonBfactor is None: + self._powderWilsonBfactor = None + elif powderWilsonBfactor.__class__.__name__ == "XSDataDouble": + self._powderWilsonBfactor = powderWilsonBfactor + else: + strMessage = "ERROR! XSDataControlImageDozor.setPowderWilsonBfactor argument is not XSDataDouble but %s" % powderWilsonBfactor.__class__.__name__ + raise BaseException(strMessage) + def delPowderWilsonBfactor(self): self._powderWilsonBfactor = None + powderWilsonBfactor = property(getPowderWilsonBfactor, setPowderWilsonBfactor, delPowderWilsonBfactor, "Property for powderWilsonBfactor") + # Methods and properties for the 'powderWilsonResolution' attribute + def getPowderWilsonResolution(self): return self._powderWilsonResolution + def setPowderWilsonResolution(self, powderWilsonResolution): + if powderWilsonResolution is None: + self._powderWilsonResolution = None + elif powderWilsonResolution.__class__.__name__ == "XSDataDouble": + self._powderWilsonResolution = powderWilsonResolution + else: + strMessage = "ERROR! XSDataControlImageDozor.setPowderWilsonResolution argument is not XSDataDouble but %s" % powderWilsonResolution.__class__.__name__ + raise BaseException(strMessage) + def delPowderWilsonResolution(self): self._powderWilsonResolution = None + powderWilsonResolution = property(getPowderWilsonResolution, setPowderWilsonResolution, delPowderWilsonResolution, "Property for powderWilsonResolution") + # Methods and properties for the 'powderWilsonCorrelation' attribute + def getPowderWilsonCorrelation(self): return self._powderWilsonCorrelation + def setPowderWilsonCorrelation(self, powderWilsonCorrelation): + if powderWilsonCorrelation is None: + self._powderWilsonCorrelation = None + elif powderWilsonCorrelation.__class__.__name__ == "XSDataDouble": + self._powderWilsonCorrelation = powderWilsonCorrelation + else: + strMessage = "ERROR! XSDataControlImageDozor.setPowderWilsonCorrelation argument is not XSDataDouble but %s" % powderWilsonCorrelation.__class__.__name__ + raise BaseException(strMessage) + def delPowderWilsonCorrelation(self): self._powderWilsonCorrelation = None + powderWilsonCorrelation = property(getPowderWilsonCorrelation, setPowderWilsonCorrelation, delPowderWilsonCorrelation, "Property for powderWilsonCorrelation") + # Methods and properties for the 'powderWilsonRfactor' attribute + def getPowderWilsonRfactor(self): return self._powderWilsonRfactor + def setPowderWilsonRfactor(self, powderWilsonRfactor): + if powderWilsonRfactor is None: + self._powderWilsonRfactor = None + elif powderWilsonRfactor.__class__.__name__ == "XSDataDouble": + self._powderWilsonRfactor = powderWilsonRfactor + else: + strMessage = "ERROR! XSDataControlImageDozor.setPowderWilsonRfactor argument is not XSDataDouble but %s" % powderWilsonRfactor.__class__.__name__ + raise BaseException(strMessage) + def delPowderWilsonRfactor(self): self._powderWilsonRfactor = None + powderWilsonRfactor = property(getPowderWilsonRfactor, setPowderWilsonRfactor, delPowderWilsonRfactor, "Property for powderWilsonRfactor") + # Methods and properties for the 'mainScore' attribute + def getMainScore(self): return self._mainScore + def setMainScore(self, mainScore): + if mainScore is None: + self._mainScore = None + elif mainScore.__class__.__name__ == "XSDataDouble": + self._mainScore = mainScore + else: + strMessage = "ERROR! XSDataControlImageDozor.setMainScore argument is not XSDataDouble but %s" % mainScore.__class__.__name__ + raise BaseException(strMessage) + def delMainScore(self): self._mainScore = None + mainScore = property(getMainScore, setMainScore, delMainScore, "Property for mainScore") + # Methods and properties for the 'spotScore' attribute + def getSpotScore(self): return self._spotScore + def setSpotScore(self, spotScore): + if spotScore is None: + self._spotScore = None + elif spotScore.__class__.__name__ == "XSDataDouble": + self._spotScore = spotScore + else: + strMessage = "ERROR! XSDataControlImageDozor.setSpotScore argument is not XSDataDouble but %s" % spotScore.__class__.__name__ + raise BaseException(strMessage) + def delSpotScore(self): self._spotScore = None + spotScore = property(getSpotScore, setSpotScore, delSpotScore, "Property for spotScore") + # Methods and properties for the 'visibleResolution' attribute + def getVisibleResolution(self): return self._visibleResolution + def setVisibleResolution(self, visibleResolution): + if visibleResolution is None: + self._visibleResolution = None + elif visibleResolution.__class__.__name__ == "XSDataDouble": + self._visibleResolution = visibleResolution + else: + strMessage = "ERROR! XSDataControlImageDozor.setVisibleResolution argument is not XSDataDouble but %s" % visibleResolution.__class__.__name__ + raise BaseException(strMessage) + def delVisibleResolution(self): self._visibleResolution = None + visibleResolution = property(getVisibleResolution, setVisibleResolution, delVisibleResolution, "Property for visibleResolution") + # Methods and properties for the 'spotFile' attribute + def getSpotFile(self): return self._spotFile + def setSpotFile(self, spotFile): + if spotFile is None: + self._spotFile = None + elif spotFile.__class__.__name__ == "XSDataFile": + self._spotFile = spotFile + else: + strMessage = "ERROR! XSDataControlImageDozor.setSpotFile argument is not XSDataFile but %s" % spotFile.__class__.__name__ + raise BaseException(strMessage) + def delSpotFile(self): self._spotFile = None + spotFile = property(getSpotFile, setSpotFile, delSpotFile, "Property for spotFile") + # Methods and properties for the 'angle' attribute + def getAngle(self): return self._angle + def setAngle(self, angle): + if angle is None: + self._angle = None + elif angle.__class__.__name__ == "XSDataAngle": + self._angle = angle + else: + strMessage = "ERROR! XSDataControlImageDozor.setAngle argument is not XSDataAngle but %s" % angle.__class__.__name__ + raise BaseException(strMessage) + def delAngle(self): self._angle = None + angle = property(getAngle, setAngle, delAngle, "Property for angle") + def export(self, outfile, level, name_='XSDataControlImageDozor'): + showIndent(outfile, level) + outfile.write(unicode('<%s>\n' % name_)) + self.exportChildren(outfile, level + 1, name_) + showIndent(outfile, level) + outfile.write(unicode('\n' % name_)) + def exportChildren(self, outfile, level, name_='XSDataControlImageDozor'): + pass + if self._number is not None: + self.number.export(outfile, level, name_='number') + else: + warnEmptyAttribute("number", "XSDataInteger") + if self._image is not None: + self.image.export(outfile, level, name_='image') + else: + warnEmptyAttribute("image", "XSDataFile") + if self._spotsNumOf is not None: + self.spotsNumOf.export(outfile, level, name_='spotsNumOf') + else: + warnEmptyAttribute("spotsNumOf", "XSDataInteger") + if self._spotsIntAver is not None: + self.spotsIntAver.export(outfile, level, name_='spotsIntAver') + else: + warnEmptyAttribute("spotsIntAver", "XSDataDouble") + if self._spotsResolution is not None: + self.spotsResolution.export(outfile, level, name_='spotsResolution') + if self._powderWilsonScale is not None: + self.powderWilsonScale.export(outfile, level, name_='powderWilsonScale') + if self._powderWilsonBfactor is not None: + self.powderWilsonBfactor.export(outfile, level, name_='powderWilsonBfactor') + if self._powderWilsonResolution is not None: + self.powderWilsonResolution.export(outfile, level, name_='powderWilsonResolution') + if self._powderWilsonCorrelation is not None: + self.powderWilsonCorrelation.export(outfile, level, name_='powderWilsonCorrelation') + if self._powderWilsonRfactor is not None: + self.powderWilsonRfactor.export(outfile, level, name_='powderWilsonRfactor') + if self._mainScore is not None: + self.mainScore.export(outfile, level, name_='mainScore') + if self._spotScore is not None: + self.spotScore.export(outfile, level, name_='spotScore') + if self._visibleResolution is not None: + self.visibleResolution.export(outfile, level, name_='visibleResolution') + if self._spotFile is not None: + self.spotFile.export(outfile, level, name_='spotFile') + if self._angle is not None: + self.angle.export(outfile, level, name_='angle') + def build(self, node_): + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'number': + obj_ = XSDataInteger() + obj_.build(child_) + self.setNumber(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'image': + obj_ = XSDataFile() + obj_.build(child_) + self.setImage(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'spotsNumOf': + obj_ = XSDataInteger() + obj_.build(child_) + self.setSpotsNumOf(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'spotsIntAver': + obj_ = XSDataDouble() + obj_.build(child_) + self.setSpotsIntAver(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'spotsResolution': + obj_ = XSDataDouble() + obj_.build(child_) + self.setSpotsResolution(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'powderWilsonScale': + obj_ = XSDataDouble() + obj_.build(child_) + self.setPowderWilsonScale(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'powderWilsonBfactor': + obj_ = XSDataDouble() + obj_.build(child_) + self.setPowderWilsonBfactor(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'powderWilsonResolution': + obj_ = XSDataDouble() + obj_.build(child_) + self.setPowderWilsonResolution(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'powderWilsonCorrelation': + obj_ = XSDataDouble() + obj_.build(child_) + self.setPowderWilsonCorrelation(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'powderWilsonRfactor': + obj_ = XSDataDouble() + obj_.build(child_) + self.setPowderWilsonRfactor(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'mainScore': + obj_ = XSDataDouble() + obj_.build(child_) + self.setMainScore(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'spotScore': + obj_ = XSDataDouble() + obj_.build(child_) + self.setSpotScore(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'visibleResolution': + obj_ = XSDataDouble() + obj_.build(child_) + self.setVisibleResolution(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'spotFile': + obj_ = XSDataFile() + obj_.build(child_) + self.setSpotFile(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'angle': + obj_ = XSDataAngle() + obj_.build(child_) + self.setAngle(obj_) + #Method for marshalling an object + def marshal( self ): + oStreamString = StringIO() + oStreamString.write(unicode('\n')) + self.export( oStreamString, 0, name_="XSDataControlImageDozor" ) + oStringXML = oStreamString.getvalue() + oStreamString.close() + return oStringXML + #Only to export the entire XML tree to a file stream on disk + def exportToFile( self, _outfileName ): + outfile = open( _outfileName, "w" ) + outfile.write(unicode('\n')) + self.export( outfile, 0, name_='XSDataControlImageDozor' ) + outfile.close() + #Deprecated method, replaced by exportToFile + def outputFile( self, _outfileName ): + print("WARNING: Method outputFile in class XSDataControlImageDozor is deprecated, please use instead exportToFile!") + self.exportToFile(_outfileName) + #Method for making a copy in a new instance + def copy( self ): + return XSDataControlImageDozor.parseString(self.marshal()) + #Static method for parsing a string + def parseString( _inString ): + doc = minidom.parseString(_inString) + rootNode = doc.documentElement + rootObj = XSDataControlImageDozor() + rootObj.build(rootNode) + # Check that all minOccurs are obeyed by marshalling the created object + oStreamString = StringIO() + rootObj.export( oStreamString, 0, name_="XSDataControlImageDozor" ) + oStreamString.close() + return rootObj + parseString = staticmethod( parseString ) + #Static method for parsing a file + def parseFile( _inFilePath ): + doc = minidom.parse(_inFilePath) + rootNode = doc.documentElement + rootObj = XSDataControlImageDozor() + rootObj.build(rootNode) + return rootObj + parseFile = staticmethod( parseFile ) +# end class XSDataControlImageDozor + + +class XSDataDozorInput(XSDataInput): + def __init__(self, configuration=None, nameTemplateImage=None, numberImages=None, firstImageNumber=None, startingAngle=None, imageStep=None, + oscillationRange=None, orgy=None, orgx=None, fractionPolarization=None, wavelength=None, detectorDistance=None, spotSize=None, exposureTime=None, detectorType=None, + ): + XSDataInput.__init__(self, configuration) + if detectorType is None: + self._detectorType = None + elif detectorType.__class__.__name__ == "XSDataString": + self._detectorType = detectorType + else: + strMessage = "ERROR! XSDataDozorInput constructor argument 'detectorType' is not XSDataString but %s" % self._detectorType.__class__.__name__ + raise BaseException(strMessage) + if exposureTime is None: + self._exposureTime = None + elif exposureTime.__class__.__name__ == "XSDataDouble": + self._exposureTime = exposureTime + else: + strMessage = "ERROR! XSDataDozorInput constructor argument 'exposureTime' is not XSDataDouble but %s" % self._exposureTime.__class__.__name__ + raise BaseException(strMessage) + if spotSize is None: + self._spotSize = None + elif spotSize.__class__.__name__ == "XSDataInteger": + self._spotSize = spotSize + else: + strMessage = "ERROR! XSDataDozorInput constructor argument 'spotSize' is not XSDataInteger but %s" % self._spotSize.__class__.__name__ + raise BaseException(strMessage) + if detectorDistance is None: + self._detectorDistance = None + elif detectorDistance.__class__.__name__ == "XSDataDouble": + self._detectorDistance = detectorDistance + else: + strMessage = "ERROR! XSDataDozorInput constructor argument 'detectorDistance' is not XSDataDouble but %s" % self._detectorDistance.__class__.__name__ + raise BaseException(strMessage) + if wavelength is None: + self._wavelength = None + elif wavelength.__class__.__name__ == "XSDataDouble": + self._wavelength = wavelength + else: + strMessage = "ERROR! XSDataDozorInput constructor argument 'wavelength' is not XSDataDouble but %s" % self._wavelength.__class__.__name__ + raise BaseException(strMessage) + if fractionPolarization is None: + self._fractionPolarization = None + elif fractionPolarization.__class__.__name__ == "XSDataDouble": + self._fractionPolarization = fractionPolarization + else: + strMessage = "ERROR! XSDataDozorInput constructor argument 'fractionPolarization' is not XSDataDouble but %s" % self._fractionPolarization.__class__.__name__ + raise BaseException(strMessage) + if orgx is None: + self._orgx = None + elif orgx.__class__.__name__ == "XSDataDouble": + self._orgx = orgx + else: + strMessage = "ERROR! XSDataDozorInput constructor argument 'orgx' is not XSDataDouble but %s" % self._orgx.__class__.__name__ + raise BaseException(strMessage) + if orgy is None: + self._orgy = None + elif orgy.__class__.__name__ == "XSDataDouble": + self._orgy = orgy + else: + strMessage = "ERROR! XSDataDozorInput constructor argument 'orgy' is not XSDataDouble but %s" % self._orgy.__class__.__name__ + raise BaseException(strMessage) + if oscillationRange is None: + self._oscillationRange = None + elif oscillationRange.__class__.__name__ == "XSDataDouble": + self._oscillationRange = oscillationRange + else: + strMessage = "ERROR! XSDataDozorInput constructor argument 'oscillationRange' is not XSDataDouble but %s" % self._oscillationRange.__class__.__name__ + raise BaseException(strMessage) + if imageStep is None: + self._imageStep = None + elif imageStep.__class__.__name__ == "XSDataDouble": + self._imageStep = imageStep + else: + strMessage = "ERROR! XSDataDozorInput constructor argument 'imageStep' is not XSDataDouble but %s" % self._imageStep.__class__.__name__ + raise BaseException(strMessage) + if startingAngle is None: + self._startingAngle = None + elif startingAngle.__class__.__name__ == "XSDataDouble": + self._startingAngle = startingAngle + else: + strMessage = "ERROR! XSDataDozorInput constructor argument 'startingAngle' is not XSDataDouble but %s" % self._startingAngle.__class__.__name__ + raise BaseException(strMessage) + if firstImageNumber is None: + self._firstImageNumber = None + elif firstImageNumber.__class__.__name__ == "XSDataInteger": + self._firstImageNumber = firstImageNumber + else: + strMessage = "ERROR! XSDataDozorInput constructor argument 'firstImageNumber' is not XSDataInteger but %s" % self._firstImageNumber.__class__.__name__ + raise BaseException(strMessage) + if numberImages is None: + self._numberImages = None + elif numberImages.__class__.__name__ == "XSDataInteger": + self._numberImages = numberImages + else: + strMessage = "ERROR! XSDataDozorInput constructor argument 'numberImages' is not XSDataInteger but %s" % self._numberImages.__class__.__name__ + raise BaseException(strMessage) + if nameTemplateImage is None: + self._nameTemplateImage = None + elif nameTemplateImage.__class__.__name__ == "XSDataString": + self._nameTemplateImage = nameTemplateImage + else: + strMessage = "ERROR! XSDataDozorInput constructor argument 'nameTemplateImage' is not XSDataString but %s" % self._nameTemplateImage.__class__.__name__ + raise BaseException(strMessage) + # Methods and properties for the 'detectorType' attribute + def getDetectorType(self): return self._detectorType + def setDetectorType(self, detectorType): + if detectorType is None: + self._detectorType = None + elif detectorType.__class__.__name__ == "XSDataString": + self._detectorType = detectorType + else: + strMessage = "ERROR! XSDataDozorInput.setDetectorType argument is not XSDataString but %s" % detectorType.__class__.__name__ + raise BaseException(strMessage) + def delDetectorType(self): self._detectorType = None + detectorType = property(getDetectorType, setDetectorType, delDetectorType, "Property for detectorType") + # Methods and properties for the 'exposureTime' attribute + def getExposureTime(self): return self._exposureTime + def setExposureTime(self, exposureTime): + if exposureTime is None: + self._exposureTime = None + elif exposureTime.__class__.__name__ == "XSDataDouble": + self._exposureTime = exposureTime + else: + strMessage = "ERROR! XSDataDozorInput.setExposureTime argument is not XSDataDouble but %s" % exposureTime.__class__.__name__ + raise BaseException(strMessage) + def delExposureTime(self): self._exposureTime = None + exposureTime = property(getExposureTime, setExposureTime, delExposureTime, "Property for exposureTime") + # Methods and properties for the 'spotSize' attribute + def getSpotSize(self): return self._spotSize + def setSpotSize(self, spotSize): + if spotSize is None: + self._spotSize = None + elif spotSize.__class__.__name__ == "XSDataInteger": + self._spotSize = spotSize + else: + strMessage = "ERROR! XSDataDozorInput.setSpotSize argument is not XSDataInteger but %s" % spotSize.__class__.__name__ + raise BaseException(strMessage) + def delSpotSize(self): self._spotSize = None + spotSize = property(getSpotSize, setSpotSize, delSpotSize, "Property for spotSize") + # Methods and properties for the 'detectorDistance' attribute + def getDetectorDistance(self): return self._detectorDistance + def setDetectorDistance(self, detectorDistance): + if detectorDistance is None: + self._detectorDistance = None + elif detectorDistance.__class__.__name__ == "XSDataDouble": + self._detectorDistance = detectorDistance + else: + strMessage = "ERROR! XSDataDozorInput.setDetectorDistance argument is not XSDataDouble but %s" % detectorDistance.__class__.__name__ + raise BaseException(strMessage) + def delDetectorDistance(self): self._detectorDistance = None + detectorDistance = property(getDetectorDistance, setDetectorDistance, delDetectorDistance, "Property for detectorDistance") + # Methods and properties for the 'wavelength' attribute + def getWavelength(self): return self._wavelength + def setWavelength(self, wavelength): + if wavelength is None: + self._wavelength = None + elif wavelength.__class__.__name__ == "XSDataDouble": + self._wavelength = wavelength + else: + strMessage = "ERROR! XSDataDozorInput.setWavelength argument is not XSDataDouble but %s" % wavelength.__class__.__name__ + raise BaseException(strMessage) + def delWavelength(self): self._wavelength = None + wavelength = property(getWavelength, setWavelength, delWavelength, "Property for wavelength") + # Methods and properties for the 'fractionPolarization' attribute + def getFractionPolarization(self): return self._fractionPolarization + def setFractionPolarization(self, fractionPolarization): + if fractionPolarization is None: + self._fractionPolarization = None + elif fractionPolarization.__class__.__name__ == "XSDataDouble": + self._fractionPolarization = fractionPolarization + else: + strMessage = "ERROR! XSDataDozorInput.setFractionPolarization argument is not XSDataDouble but %s" % fractionPolarization.__class__.__name__ + raise BaseException(strMessage) + def delFractionPolarization(self): self._fractionPolarization = None + fractionPolarization = property(getFractionPolarization, setFractionPolarization, delFractionPolarization, "Property for fractionPolarization") + # Methods and properties for the 'orgx' attribute + def getOrgx(self): return self._orgx + def setOrgx(self, orgx): + if orgx is None: + self._orgx = None + elif orgx.__class__.__name__ == "XSDataDouble": + self._orgx = orgx + else: + strMessage = "ERROR! XSDataDozorInput.setOrgx argument is not XSDataDouble but %s" % orgx.__class__.__name__ + raise BaseException(strMessage) + def delOrgx(self): self._orgx = None + orgx = property(getOrgx, setOrgx, delOrgx, "Property for orgx") + # Methods and properties for the 'orgy' attribute + def getOrgy(self): return self._orgy + def setOrgy(self, orgy): + if orgy is None: + self._orgy = None + elif orgy.__class__.__name__ == "XSDataDouble": + self._orgy = orgy + else: + strMessage = "ERROR! XSDataDozorInput.setOrgy argument is not XSDataDouble but %s" % orgy.__class__.__name__ + raise BaseException(strMessage) + def delOrgy(self): self._orgy = None + orgy = property(getOrgy, setOrgy, delOrgy, "Property for orgy") + # Methods and properties for the 'oscillationRange' attribute + def getOscillationRange(self): return self._oscillationRange + def setOscillationRange(self, oscillationRange): + if oscillationRange is None: + self._oscillationRange = None + elif oscillationRange.__class__.__name__ == "XSDataDouble": + self._oscillationRange = oscillationRange + else: + strMessage = "ERROR! XSDataDozorInput.setOscillationRange argument is not XSDataDouble but %s" % oscillationRange.__class__.__name__ + raise BaseException(strMessage) + def delOscillationRange(self): self._oscillationRange = None + oscillationRange = property(getOscillationRange, setOscillationRange, delOscillationRange, "Property for oscillationRange") + # Methods and properties for the 'imageStep' attribute + def getImageStep(self): return self._imageStep + def setImageStep(self, imageStep): + if imageStep is None: + self._imageStep = None + elif imageStep.__class__.__name__ == "XSDataDouble": + self._imageStep = imageStep + else: + strMessage = "ERROR! XSDataDozorInput.setImageStep argument is not XSDataDouble but %s" % imageStep.__class__.__name__ + raise BaseException(strMessage) + def delImageStep(self): self._imageStep = None + imageStep = property(getImageStep, setImageStep, delImageStep, "Property for imageStep") + # Methods and properties for the 'startingAngle' attribute + def getStartingAngle(self): return self._startingAngle + def setStartingAngle(self, startingAngle): + if startingAngle is None: + self._startingAngle = None + elif startingAngle.__class__.__name__ == "XSDataDouble": + self._startingAngle = startingAngle + else: + strMessage = "ERROR! XSDataDozorInput.setStartingAngle argument is not XSDataDouble but %s" % startingAngle.__class__.__name__ + raise BaseException(strMessage) + def delStartingAngle(self): self._startingAngle = None + startingAngle = property(getStartingAngle, setStartingAngle, delStartingAngle, "Property for startingAngle") + # Methods and properties for the 'firstImageNumber' attribute + def getFirstImageNumber(self): return self._firstImageNumber + def setFirstImageNumber(self, firstImageNumber): + if firstImageNumber is None: + self._firstImageNumber = None + elif firstImageNumber.__class__.__name__ == "XSDataInteger": + self._firstImageNumber = firstImageNumber + else: + strMessage = "ERROR! XSDataDozorInput.setFirstImageNumber argument is not XSDataInteger but %s" % firstImageNumber.__class__.__name__ + raise BaseException(strMessage) + def delFirstImageNumber(self): self._firstImageNumber = None + firstImageNumber = property(getFirstImageNumber, setFirstImageNumber, delFirstImageNumber, "Property for firstImageNumber") + # Methods and properties for the 'numberImages' attribute + def getNumberImages(self): return self._numberImages + def setNumberImages(self, numberImages): + if numberImages is None: + self._numberImages = None + elif numberImages.__class__.__name__ == "XSDataInteger": + self._numberImages = numberImages + else: + strMessage = "ERROR! XSDataDozorInput.setNumberImages argument is not XSDataInteger but %s" % numberImages.__class__.__name__ + raise BaseException(strMessage) + def delNumberImages(self): self._numberImages = None + numberImages = property(getNumberImages, setNumberImages, delNumberImages, "Property for numberImages") + # Methods and properties for the 'nameTemplateImage' attribute + def getNameTemplateImage(self): return self._nameTemplateImage + def setNameTemplateImage(self, nameTemplateImage): + if nameTemplateImage is None: + self._nameTemplateImage = None + elif nameTemplateImage.__class__.__name__ == "XSDataString": + self._nameTemplateImage = nameTemplateImage + else: + strMessage = "ERROR! XSDataDozorInput.setNameTemplateImage argument is not XSDataString but %s" % nameTemplateImage.__class__.__name__ + raise BaseException(strMessage) + def delNameTemplateImage(self): self._nameTemplateImage = None + nameTemplateImage = property(getNameTemplateImage, setNameTemplateImage, delNameTemplateImage, "Property for nameTemplateImage") + + def export(self, outfile, level, name_='XSDataDozorInput'): + showIndent(outfile, level) + outfile.write(unicode('<%s>\n' % name_)) + self.exportChildren(outfile, level + 1, name_) + showIndent(outfile, level) + outfile.write(unicode('\n' % name_)) + def exportChildren(self, outfile, level, name_='XSDataDozorInput'): + XSDataInput.exportChildren(self, outfile, level, name_) + if self._detectorType is not None: + self.detectorType.export(outfile, level, name_='detectorType') + else: + warnEmptyAttribute("detectorType", "XSDataString") + if self._exposureTime is not None: + self.exposureTime.export(outfile, level, name_='exposureTime') + else: + warnEmptyAttribute("exposureTime", "XSDataDouble") + if self._spotSize is not None: + self.spotSize.export(outfile, level, name_='spotSize') + else: + warnEmptyAttribute("spotSize", "XSDataInteger") + if self._detectorDistance is not None: + self.detectorDistance.export(outfile, level, name_='detectorDistance') + else: + warnEmptyAttribute("detectorDistance", "XSDataDouble") + if self._wavelength is not None: + self.wavelength.export(outfile, level, name_='wavelength') + else: + warnEmptyAttribute("wavelength", "XSDataDouble") + if self._fractionPolarization is not None: + self.fractionPolarization.export(outfile, level, name_='fractionPolarization') + if self._orgx is not None: + self.orgx.export(outfile, level, name_='orgx') + else: + warnEmptyAttribute("orgx", "XSDataDouble") + if self._orgy is not None: + self.orgy.export(outfile, level, name_='orgy') + else: + warnEmptyAttribute("orgy", "XSDataDouble") + if self._oscillationRange is not None: + self.oscillationRange.export(outfile, level, name_='oscillationRange') + else: + warnEmptyAttribute("oscillationRange", "XSDataDouble") + if self._imageStep is not None: + self.imageStep.export(outfile, level, name_='imageStep') + if self._startingAngle is not None: + self.startingAngle.export(outfile, level, name_='startingAngle') + if self._firstImageNumber is not None: + self.firstImageNumber.export(outfile, level, name_='firstImageNumber') + else: + warnEmptyAttribute("firstImageNumber", "XSDataInteger") + if self._numberImages is not None: + self.numberImages.export(outfile, level, name_='numberImages') + else: + warnEmptyAttribute("numberImages", "XSDataInteger") + if self._nameTemplateImage is not None: + self.nameTemplateImage.export(outfile, level, name_='nameTemplateImage') + else: + warnEmptyAttribute("nameTemplateImage", "XSDataString") + + def build(self, node_): + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'detectorType': + obj_ = XSDataString() + obj_.build(child_) + self.setDetectorType(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'exposureTime': + obj_ = XSDataDouble() + obj_.build(child_) + self.setExposureTime(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'spotSize': + obj_ = XSDataInteger() + obj_.build(child_) + self.setSpotSize(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'detectorDistance': + obj_ = XSDataDouble() + obj_.build(child_) + self.setDetectorDistance(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'wavelength': + obj_ = XSDataDouble() + obj_.build(child_) + self.setWavelength(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'fractionPolarization': + obj_ = XSDataDouble() + obj_.build(child_) + self.setFractionPolarization(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'orgx': + obj_ = XSDataDouble() + obj_.build(child_) + self.setOrgx(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'orgy': + obj_ = XSDataDouble() + obj_.build(child_) + self.setOrgy(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'oscillationRange': + obj_ = XSDataDouble() + obj_.build(child_) + self.setOscillationRange(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'imageStep': + obj_ = XSDataDouble() + obj_.build(child_) + self.setImageStep(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'startingAngle': + obj_ = XSDataDouble() + obj_.build(child_) + self.setStartingAngle(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'firstImageNumber': + obj_ = XSDataInteger() + obj_.build(child_) + self.setFirstImageNumber(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'numberImages': + obj_ = XSDataInteger() + obj_.build(child_) + self.setNumberImages(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'nameTemplateImage': + obj_ = XSDataString() + obj_.build(child_) + self.setNameTemplateImage(obj_) + XSDataInput.buildChildren(self, child_, nodeName_) + #Method for marshalling an object + def marshal( self ): + oStreamString = StringIO() + oStreamString.write(unicode('\n')) + self.export( oStreamString, 0, name_="XSDataDozorInput" ) + oStringXML = oStreamString.getvalue() + oStreamString.close() + return oStringXML + #Only to export the entire XML tree to a file stream on disk + def exportToFile( self, _outfileName ): + outfile = open( _outfileName, "w" ) + outfile.write(unicode('\n')) + self.export( outfile, 0, name_='XSDataDozorInput' ) + outfile.close() + #Deprecated method, replaced by exportToFile + def outputFile( self, _outfileName ): + print("WARNING: Method outputFile in class XSDataDozorInput is deprecated, please use instead exportToFile!") + self.exportToFile(_outfileName) + #Method for making a copy in a new instance + def copy( self ): + return XSDataDozorInput.parseString(self.marshal()) + #Static method for parsing a string + def parseString( _inString ): + doc = minidom.parseString(_inString) + rootNode = doc.documentElement + rootObj = XSDataDozorInput() + rootObj.build(rootNode) + # Check that all minOccurs are obeyed by marshalling the created object + oStreamString = StringIO() + rootObj.export( oStreamString, 0, name_="XSDataDozorInput" ) + oStreamString.close() + return rootObj + parseString = staticmethod( parseString ) + #Static method for parsing a file + def parseFile( _inFilePath ): + doc = minidom.parse(_inFilePath) + rootNode = doc.documentElement + rootObj = XSDataDozorInput() + rootObj.build(rootNode) + return rootObj + parseFile = staticmethod( parseFile ) +# end class XSDataDozorInput + + +class XSDataInputControlDozor(XSDataInput): + def __init__(self, configuration=None, keepCbfTmpDirectory=None, radiationDamage=None, wedgeNumber=None, + hdf5BatchSize=None, batchSize=None, endNo=None, startNo=None, template=None, directory=None, image=None, processDirectory=None, dataCollectionId=None, + doISPyBUpload=None + ): + XSDataInput.__init__(self, configuration) + if dataCollectionId is None: + self._dataCollectionId = None + elif dataCollectionId.__class__.__name__ == "XSDataInteger": + self._dataCollectionId = dataCollectionId + else: + strMessage = "ERROR! XSDataInputControlDozor constructor argument 'dataCollectionId' is not XSDataInteger but %s" % self._dataCollectionId.__class__.__name__ + raise BaseException(strMessage) + if processDirectory is None: + self._processDirectory = None + elif processDirectory.__class__.__name__ == "XSDataFile": + self._processDirectory = processDirectory + else: + strMessage = "ERROR! XSDataInputControlDozor constructor argument 'processDirectory' is not XSDataFile but %s" % self._processDirectory.__class__.__name__ + raise BaseException(strMessage) + if image is None: + self._image = [] + elif image.__class__.__name__ == "list": + self._image = image + else: + strMessage = "ERROR! XSDataInputControlDozor constructor argument 'image' is not list but %s" % self._image.__class__.__name__ + raise BaseException(strMessage) + if directory is None: + self._directory = None + elif directory.__class__.__name__ == "XSDataFile": + self._directory = directory + else: + strMessage = "ERROR! XSDataInputControlDozor constructor argument 'directory' is not XSDataFile but %s" % self._directory.__class__.__name__ + raise BaseException(strMessage) + if template is None: + self._template = None + elif template.__class__.__name__ == "XSDataString": + self._template = template + else: + strMessage = "ERROR! XSDataInputControlDozor constructor argument 'template' is not XSDataString but %s" % self._template.__class__.__name__ + raise BaseException(strMessage) + if startNo is None: + self._startNo = None + elif startNo.__class__.__name__ == "XSDataInteger": + self._startNo = startNo + else: + strMessage = "ERROR! XSDataInputControlDozor constructor argument 'startNo' is not XSDataInteger but %s" % self._startNo.__class__.__name__ + raise BaseException(strMessage) + if endNo is None: + self._endNo = None + elif endNo.__class__.__name__ == "XSDataInteger": + self._endNo = endNo + else: + strMessage = "ERROR! XSDataInputControlDozor constructor argument 'endNo' is not XSDataInteger but %s" % self._endNo.__class__.__name__ + raise BaseException(strMessage) + if batchSize is None: + self._batchSize = None + elif batchSize.__class__.__name__ == "XSDataInteger": + self._batchSize = batchSize + else: + strMessage = "ERROR! XSDataInputControlDozor constructor argument 'batchSize' is not XSDataInteger but %s" % self._batchSize.__class__.__name__ + raise BaseException(strMessage) + if hdf5BatchSize is None: + self._hdf5BatchSize = None + elif hdf5BatchSize.__class__.__name__ == "XSDataInteger": + self._hdf5BatchSize = hdf5BatchSize + else: + strMessage = "ERROR! XSDataInputControlDozor constructor argument 'hdf5BatchSize' is not XSDataInteger but %s" % self._hdf5BatchSize.__class__.__name__ + raise BaseException(strMessage) + if wedgeNumber is None: + self._wedgeNumber = None + elif wedgeNumber.__class__.__name__ == "XSDataInteger": + self._wedgeNumber = wedgeNumber + else: + strMessage = "ERROR! XSDataInputControlDozor constructor argument 'wedgeNumber' is not XSDataInteger but %s" % self._wedgeNumber.__class__.__name__ + raise BaseException(strMessage) + if radiationDamage is None: + self._radiationDamage = None + elif radiationDamage.__class__.__name__ == "XSDataBoolean": + self._radiationDamage = radiationDamage + else: + strMessage = "ERROR! XSDataInputControlDozor constructor argument 'radiationDamage' is not XSDataBoolean but %s" % self._radiationDamage.__class__.__name__ + raise BaseException(strMessage) + if keepCbfTmpDirectory is None: + self._keepCbfTmpDirectory = None + elif keepCbfTmpDirectory.__class__.__name__ == "XSDataBoolean": + self._keepCbfTmpDirectory = keepCbfTmpDirectory + else: + strMessage = "ERROR! XSDataInputControlDozor constructor argument 'keepCbfTmpDirectory' is not XSDataBoolean but %s" % self._keepCbfTmpDirectory.__class__.__name__ + raise BaseException(strMessage) + if doISPyBUpload is None: + self._doISPyBUpload = None + elif doISPyBUpload.__class__.__name__ == "XSDataBoolean": + self._doISPyBUpload = doISPyBUpload + else: + strMessage = ( + "ERROR! XSDataControlImageDozor constructor argument 'doISPyBUpload' is not XSDataBoolean but %s" + % self._doISPyBUpload.__class__.__name__ + ) + raise Exception(strMessage) + # Methods and properties for the 'dataCollectionId' attribute + def getDataCollectionId(self): return self._dataCollectionId + def setDataCollectionId(self, dataCollectionId): + if dataCollectionId is None: + self._dataCollectionId = None + elif dataCollectionId.__class__.__name__ == "XSDataInteger": + self._dataCollectionId = dataCollectionId + else: + strMessage = "ERROR! XSDataInputControlDozor.setDataCollectionId argument is not XSDataInteger but %s" % dataCollectionId.__class__.__name__ + raise BaseException(strMessage) + def delDataCollectionId(self): self._dataCollectionId = None + dataCollectionId = property(getDataCollectionId, setDataCollectionId, delDataCollectionId, "Property for dataCollectionId") + # Methods and properties for the 'processDirectory' attribute + def getProcessDirectory(self): return self._processDirectory + def setProcessDirectory(self, processDirectory): + if processDirectory is None: + self._processDirectory = None + elif processDirectory.__class__.__name__ == "XSDataFile": + self._processDirectory = processDirectory + else: + strMessage = "ERROR! XSDataInputControlDozor.setProcessDirectory argument is not XSDataFile but %s" % processDirectory.__class__.__name__ + raise BaseException(strMessage) + def delProcessDirectory(self): self._processDirectory = None + processDirectory = property(getProcessDirectory, setProcessDirectory, delProcessDirectory, "Property for processDirectory") + # Methods and properties for the 'image' attribute + def getImage(self): return self._image + def setImage(self, image): + if image is None: + self._image = [] + elif image.__class__.__name__ == "list": + self._image = image + else: + strMessage = "ERROR! XSDataInputControlDozor.setImage argument is not list but %s" % image.__class__.__name__ + raise BaseException(strMessage) + def delImage(self): self._image = None + image = property(getImage, setImage, delImage, "Property for image") + def addImage(self, value): + if value is None: + strMessage = "ERROR! XSDataInputControlDozor.addImage argument is None" + raise BaseException(strMessage) + elif value.__class__.__name__ == "XSDataFile": + self._image.append(value) + else: + strMessage = "ERROR! XSDataInputControlDozor.addImage argument is not XSDataFile but %s" % value.__class__.__name__ + raise BaseException(strMessage) + def insertImage(self, index, value): + if index is None: + strMessage = "ERROR! XSDataInputControlDozor.insertImage argument 'index' is None" + raise BaseException(strMessage) + if value is None: + strMessage = "ERROR! XSDataInputControlDozor.insertImage argument 'value' is None" + raise BaseException(strMessage) + elif value.__class__.__name__ == "XSDataFile": + self._image[index] = value + else: + strMessage = "ERROR! XSDataInputControlDozor.addImage argument is not XSDataFile but %s" % value.__class__.__name__ + raise BaseException(strMessage) + # Methods and properties for the 'directory' attribute + def getDirectory(self): return self._directory + def setDirectory(self, directory): + if directory is None: + self._directory = None + elif directory.__class__.__name__ == "XSDataFile": + self._directory = directory + else: + strMessage = "ERROR! XSDataInputControlDozor.setDirectory argument is not XSDataFile but %s" % directory.__class__.__name__ + raise BaseException(strMessage) + def delDirectory(self): self._directory = None + directory = property(getDirectory, setDirectory, delDirectory, "Property for directory") + # Methods and properties for the 'template' attribute + def getTemplate(self): return self._template + def setTemplate(self, template): + if template is None: + self._template = None + elif template.__class__.__name__ == "XSDataString": + self._template = template + else: + strMessage = "ERROR! XSDataInputControlDozor.setTemplate argument is not XSDataString but %s" % template.__class__.__name__ + raise BaseException(strMessage) + def delTemplate(self): self._template = None + template = property(getTemplate, setTemplate, delTemplate, "Property for template") + # Methods and properties for the 'startNo' attribute + def getStartNo(self): return self._startNo + def setStartNo(self, startNo): + if startNo is None: + self._startNo = None + elif startNo.__class__.__name__ == "XSDataInteger": + self._startNo = startNo + else: + strMessage = "ERROR! XSDataInputControlDozor.setStartNo argument is not XSDataInteger but %s" % startNo.__class__.__name__ + raise BaseException(strMessage) + def delStartNo(self): self._startNo = None + startNo = property(getStartNo, setStartNo, delStartNo, "Property for startNo") + # Methods and properties for the 'endNo' attribute + def getEndNo(self): return self._endNo + def setEndNo(self, endNo): + if endNo is None: + self._endNo = None + elif endNo.__class__.__name__ == "XSDataInteger": + self._endNo = endNo + else: + strMessage = "ERROR! XSDataInputControlDozor.setEndNo argument is not XSDataInteger but %s" % endNo.__class__.__name__ + raise BaseException(strMessage) + def delEndNo(self): self._endNo = None + endNo = property(getEndNo, setEndNo, delEndNo, "Property for endNo") + # Methods and properties for the 'batchSize' attribute + def getBatchSize(self): return self._batchSize + def setBatchSize(self, batchSize): + if batchSize is None: + self._batchSize = None + elif batchSize.__class__.__name__ == "XSDataInteger": + self._batchSize = batchSize + else: + strMessage = "ERROR! XSDataInputControlDozor.setBatchSize argument is not XSDataInteger but %s" % batchSize.__class__.__name__ + raise BaseException(strMessage) + def delBatchSize(self): self._batchSize = None + batchSize = property(getBatchSize, setBatchSize, delBatchSize, "Property for batchSize") + # Methods and properties for the 'hdf5BatchSize' attribute + def getHdf5BatchSize(self): return self._hdf5BatchSize + def setHdf5BatchSize(self, hdf5BatchSize): + if hdf5BatchSize is None: + self._hdf5BatchSize = None + elif hdf5BatchSize.__class__.__name__ == "XSDataInteger": + self._hdf5BatchSize = hdf5BatchSize + else: + strMessage = "ERROR! XSDataInputControlDozor.setHdf5BatchSize argument is not XSDataInteger but %s" % hdf5BatchSize.__class__.__name__ + raise BaseException(strMessage) + def delHdf5BatchSize(self): self._hdf5BatchSize = None + hdf5BatchSize = property(getHdf5BatchSize, setHdf5BatchSize, delHdf5BatchSize, "Property for hdf5BatchSize") + # Methods and properties for the 'wedgeNumber' attribute + def getWedgeNumber(self): return self._wedgeNumber + def setWedgeNumber(self, wedgeNumber): + if wedgeNumber is None: + self._wedgeNumber = None + elif wedgeNumber.__class__.__name__ == "XSDataInteger": + self._wedgeNumber = wedgeNumber + else: + strMessage = "ERROR! XSDataInputControlDozor.setWedgeNumber argument is not XSDataInteger but %s" % wedgeNumber.__class__.__name__ + raise BaseException(strMessage) + def delWedgeNumber(self): self._wedgeNumber = None + wedgeNumber = property(getWedgeNumber, setWedgeNumber, delWedgeNumber, "Property for wedgeNumber") + # Methods and properties for the 'radiationDamage' attribute + def getRadiationDamage(self): return self._radiationDamage + def setRadiationDamage(self, radiationDamage): + if radiationDamage is None: + self._radiationDamage = None + elif radiationDamage.__class__.__name__ == "XSDataBoolean": + self._radiationDamage = radiationDamage + else: + strMessage = "ERROR! XSDataInputControlDozor.setRadiationDamage argument is not XSDataBoolean but %s" % radiationDamage.__class__.__name__ + raise BaseException(strMessage) + def delRadiationDamage(self): self._radiationDamage = None + radiationDamage = property(getRadiationDamage, setRadiationDamage, delRadiationDamage, "Property for radiationDamage") + # Methods and properties for the 'keepCbfTmpDirectory' attribute + def getKeepCbfTmpDirectory(self): return self._keepCbfTmpDirectory + def setKeepCbfTmpDirectory(self, keepCbfTmpDirectory): + if keepCbfTmpDirectory is None: + self._keepCbfTmpDirectory = None + elif keepCbfTmpDirectory.__class__.__name__ == "XSDataBoolean": + self._keepCbfTmpDirectory = keepCbfTmpDirectory + else: + strMessage = "ERROR! XSDataInputControlDozor.setKeepCbfTmpDirectory argument is not XSDataBoolean but %s" % keepCbfTmpDirectory.__class__.__name__ + raise BaseException(strMessage) + def delKeepCbfTmpDirectory(self): self._keepCbfTmpDirectory = None + keepCbfTmpDirectory = property(getKeepCbfTmpDirectory, setKeepCbfTmpDirectory, delKeepCbfTmpDirectory, "Property for keepCbfTmpDirectory") + # Methods and properties for the 'doISPyBUpload' attribute + def getDoISPyBUpload(self): + return self._doISPyBUpload + + def setDoISPyBUpload(self, doISPyBUpload): + if doISPyBUpload is None: + self._doISPyBUpload = None + elif doISPyBUpload.__class__.__name__ == "XSDataBoolean": + self._doISPyBUpload = doISPyBUpload + else: + strMessage = ( + "ERROR! XSDataInputControlDozor.setDoISPyBUpload argument is not XSDataBoolean but %s" + % doISPyBUpload.__class__.__name__ + ) + raise Exception(strMessage) + def delDoISPyBUpload(self): + self._doISPyBUpload = None + doISPyBUpload = property( + getDoISPyBUpload, + setDoISPyBUpload, + delDoISPyBUpload, + "Property for doISPyBUpload", + ) + + def export(self, outfile, level, name_='XSDataInputControlDozor'): + showIndent(outfile, level) + outfile.write(unicode('<%s>\n' % name_)) + self.exportChildren(outfile, level + 1, name_) + showIndent(outfile, level) + outfile.write(unicode('\n' % name_)) + def exportChildren(self, outfile, level, name_='XSDataInputControlDozor'): + XSDataInput.exportChildren(self, outfile, level, name_) + if self._dataCollectionId is not None: + self.dataCollectionId.export(outfile, level, name_='dataCollectionId') + if self._processDirectory is not None: + self.processDirectory.export(outfile, level, name_='processDirectory') + for image_ in self.getImage(): + image_.export(outfile, level, name_='image') + if self._directory is not None: + self.directory.export(outfile, level, name_='directory') + if self._template is not None: + self.template.export(outfile, level, name_='template') + if self._startNo is not None: + self.startNo.export(outfile, level, name_='startNo') + if self._endNo is not None: + self.endNo.export(outfile, level, name_='endNo') + if self._batchSize is not None: + self.batchSize.export(outfile, level, name_='batchSize') + if self._hdf5BatchSize is not None: + self.hdf5BatchSize.export(outfile, level, name_='hdf5BatchSize') + if self._wedgeNumber is not None: + self.wedgeNumber.export(outfile, level, name_='wedgeNumber') + if self._radiationDamage is not None: + self.radiationDamage.export(outfile, level, name_='radiationDamage') + if self._keepCbfTmpDirectory is not None: + self.keepCbfTmpDirectory.export(outfile, level, name_='keepCbfTmpDirectory') + if self._doISPyBUpload is not None: + self.doISPyBUpload.export(outfile, level, name_="doISPyBUpload") + def build(self, node_): + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'dataCollectionId': + obj_ = XSDataInteger() + obj_.build(child_) + self.setDataCollectionId(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'processDirectory': + obj_ = XSDataFile() + obj_.build(child_) + self.setProcessDirectory(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'image': + obj_ = XSDataFile() + obj_.build(child_) + self.image.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'directory': + obj_ = XSDataFile() + obj_.build(child_) + self.setDirectory(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'template': + obj_ = XSDataString() + obj_.build(child_) + self.setTemplate(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'startNo': + obj_ = XSDataInteger() + obj_.build(child_) + self.setStartNo(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'endNo': + obj_ = XSDataInteger() + obj_.build(child_) + self.setEndNo(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'batchSize': + obj_ = XSDataInteger() + obj_.build(child_) + self.setBatchSize(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'hdf5BatchSize': + obj_ = XSDataInteger() + obj_.build(child_) + self.setHdf5BatchSize(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'wedgeNumber': + obj_ = XSDataInteger() + obj_.build(child_) + self.setWedgeNumber(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'radiationDamage': + obj_ = XSDataBoolean() + obj_.build(child_) + self.setRadiationDamage(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'keepCbfTmpDirectory': + obj_ = XSDataBoolean() + obj_.build(child_) + self.setKeepCbfTmpDirectory(obj_) + elif ( + child_.nodeType == Node.ELEMENT_NODE + and nodeName_ == "doISPyBUpload" + ): + obj_ = XSDataBoolean() + obj_.build(child_) + self.setScore(obj_) + XSDataInput.buildChildren(self, child_, nodeName_) + #Method for marshalling an object + def marshal( self ): + oStreamString = StringIO() + oStreamString.write(unicode('\n')) + self.export( oStreamString, 0, name_="XSDataInputControlDozor" ) + oStringXML = oStreamString.getvalue() + oStreamString.close() + return oStringXML + #Only to export the entire XML tree to a file stream on disk + def exportToFile( self, _outfileName ): + outfile = open( _outfileName, "w" ) + outfile.write(unicode('\n')) + self.export( outfile, 0, name_='XSDataInputControlDozor' ) + outfile.close() + #Deprecated method, replaced by exportToFile + def outputFile( self, _outfileName ): + print("WARNING: Method outputFile in class XSDataInputControlDozor is deprecated, please use instead exportToFile!") + self.exportToFile(_outfileName) + #Method for making a copy in a new instance + def copy( self ): + return XSDataInputControlDozor.parseString(self.marshal()) + #Static method for parsing a string + def parseString( _inString ): + doc = minidom.parseString(_inString) + rootNode = doc.documentElement + rootObj = XSDataInputControlDozor() + rootObj.build(rootNode) + # Check that all minOccurs are obeyed by marshalling the created object + oStreamString = StringIO() + rootObj.export( oStreamString, 0, name_="XSDataInputControlDozor" ) + oStreamString.close() + return rootObj + parseString = staticmethod( parseString ) + #Static method for parsing a file + def parseFile( _inFilePath ): + doc = minidom.parse(_inFilePath) + rootNode = doc.documentElement + rootObj = XSDataInputControlDozor() + rootObj.build(rootNode) + return rootObj + parseFile = staticmethod( parseFile ) +# end class XSDataInputControlDozor + + +class XSDataResultControlDozor(XSDataResult): + def __init__(self, status=None, pngPlots=None, pathToCbfDirectory=None, dozorPlot=None, halfDoseTime=None, inputDozor=None, imageDozor=None): + XSDataResult.__init__(self, status) + if imageDozor is None: + self._imageDozor = [] + elif imageDozor.__class__.__name__ == "list": + self._imageDozor = imageDozor + else: + strMessage = "ERROR! XSDataResultControlDozor constructor argument 'imageDozor' is not list but %s" % self._imageDozor.__class__.__name__ + raise BaseException(strMessage) + if inputDozor is None: + self._inputDozor = None + elif inputDozor.__class__.__name__ == "XSDataDozorInput": + self._inputDozor = inputDozor + else: + strMessage = "ERROR! XSDataResultControlDozor constructor argument 'inputDozor' is not XSDataDozorInput but %s" % self._inputDozor.__class__.__name__ + raise BaseException(strMessage) + if halfDoseTime is None: + self._halfDoseTime = None + elif halfDoseTime.__class__.__name__ == "XSDataDouble": + self._halfDoseTime = halfDoseTime + else: + strMessage = "ERROR! XSDataResultControlDozor constructor argument 'halfDoseTime' is not XSDataDouble but %s" % self._halfDoseTime.__class__.__name__ + raise BaseException(strMessage) + if dozorPlot is None: + self._dozorPlot = None + elif dozorPlot.__class__.__name__ == "XSDataFile": + self._dozorPlot = dozorPlot + else: + strMessage = "ERROR! XSDataResultControlDozor constructor argument 'dozorPlot' is not XSDataFile but %s" % self._dozorPlot.__class__.__name__ + raise BaseException(strMessage) + if pathToCbfDirectory is None: + self._pathToCbfDirectory = None + elif pathToCbfDirectory.__class__.__name__ == "XSDataFile": + self._pathToCbfDirectory = pathToCbfDirectory + else: + strMessage = "ERROR! XSDataResultControlDozor constructor argument 'pathToCbfDirectory' is not XSDataFile but %s" % self._pathToCbfDirectory.__class__.__name__ + raise BaseException(strMessage) + if pngPlots is None: + self._pngPlots = [] + elif pngPlots.__class__.__name__ == "list": + self._pngPlots = pngPlots + else: + strMessage = "ERROR! XSDataResultControlDozor constructor argument 'pngPlots' is not list but %s" % self._pngPlots.__class__.__name__ + raise BaseException(strMessage) + # Methods and properties for the 'imageDozor' attribute + def getImageDozor(self): return self._imageDozor + def setImageDozor(self, imageDozor): + if imageDozor is None: + self._imageDozor = [] + elif imageDozor.__class__.__name__ == "list": + self._imageDozor = imageDozor + else: + strMessage = "ERROR! XSDataResultControlDozor.setImageDozor argument is not list but %s" % imageDozor.__class__.__name__ + raise BaseException(strMessage) + def delImageDozor(self): self._imageDozor = None + imageDozor = property(getImageDozor, setImageDozor, delImageDozor, "Property for imageDozor") + def addImageDozor(self, value): + if value is None: + strMessage = "ERROR! XSDataResultControlDozor.addImageDozor argument is None" + raise BaseException(strMessage) + elif value.__class__.__name__ == "XSDataControlImageDozor": + self._imageDozor.append(value) + else: + strMessage = "ERROR! XSDataResultControlDozor.addImageDozor argument is not XSDataControlImageDozor but %s" % value.__class__.__name__ + raise BaseException(strMessage) + def insertImageDozor(self, index, value): + if index is None: + strMessage = "ERROR! XSDataResultControlDozor.insertImageDozor argument 'index' is None" + raise BaseException(strMessage) + if value is None: + strMessage = "ERROR! XSDataResultControlDozor.insertImageDozor argument 'value' is None" + raise BaseException(strMessage) + elif value.__class__.__name__ == "XSDataControlImageDozor": + self._imageDozor[index] = value + else: + strMessage = "ERROR! XSDataResultControlDozor.addImageDozor argument is not XSDataControlImageDozor but %s" % value.__class__.__name__ + raise BaseException(strMessage) + # Methods and properties for the 'inputDozor' attribute + def getInputDozor(self): return self._inputDozor + def setInputDozor(self, inputDozor): + if inputDozor is None: + self._inputDozor = None + elif inputDozor.__class__.__name__ == "XSDataDozorInput": + self._inputDozor = inputDozor + else: + strMessage = "ERROR! XSDataResultControlDozor.setInputDozor argument is not XSDataDozorInput but %s" % inputDozor.__class__.__name__ + raise BaseException(strMessage) + def delInputDozor(self): self._inputDozor = None + inputDozor = property(getInputDozor, setInputDozor, delInputDozor, "Property for inputDozor") + # Methods and properties for the 'halfDoseTime' attribute + def getHalfDoseTime(self): return self._halfDoseTime + def setHalfDoseTime(self, halfDoseTime): + if halfDoseTime is None: + self._halfDoseTime = None + elif halfDoseTime.__class__.__name__ == "XSDataDouble": + self._halfDoseTime = halfDoseTime + else: + strMessage = "ERROR! XSDataResultControlDozor.setHalfDoseTime argument is not XSDataDouble but %s" % halfDoseTime.__class__.__name__ + raise BaseException(strMessage) + def delHalfDoseTime(self): self._halfDoseTime = None + halfDoseTime = property(getHalfDoseTime, setHalfDoseTime, delHalfDoseTime, "Property for halfDoseTime") + # Methods and properties for the 'dozorPlot' attribute + def getDozorPlot(self): return self._dozorPlot + def setDozorPlot(self, dozorPlot): + if dozorPlot is None: + self._dozorPlot = None + elif dozorPlot.__class__.__name__ == "XSDataFile": + self._dozorPlot = dozorPlot + else: + strMessage = "ERROR! XSDataResultControlDozor.setDozorPlot argument is not XSDataFile but %s" % dozorPlot.__class__.__name__ + raise BaseException(strMessage) + def delDozorPlot(self): self._dozorPlot = None + dozorPlot = property(getDozorPlot, setDozorPlot, delDozorPlot, "Property for dozorPlot") + # Methods and properties for the 'pathToCbfDirectory' attribute + def getPathToCbfDirectory(self): return self._pathToCbfDirectory + def setPathToCbfDirectory(self, pathToCbfDirectory): + if pathToCbfDirectory is None: + self._pathToCbfDirectory = None + elif pathToCbfDirectory.__class__.__name__ == "XSDataFile": + self._pathToCbfDirectory = pathToCbfDirectory + else: + strMessage = "ERROR! XSDataResultControlDozor.setPathToCbfDirectory argument is not XSDataFile but %s" % pathToCbfDirectory.__class__.__name__ + raise BaseException(strMessage) + def delPathToCbfDirectory(self): self._pathToCbfDirectory = None + pathToCbfDirectory = property(getPathToCbfDirectory, setPathToCbfDirectory, delPathToCbfDirectory, "Property for pathToCbfDirectory") + # Methods and properties for the 'pngPlots' attribute + def getPngPlots(self): return self._pngPlots + def setPngPlots(self, pngPlots): + if pngPlots is None: + self._pngPlots = [] + elif pngPlots.__class__.__name__ == "list": + self._pngPlots = pngPlots + else: + strMessage = "ERROR! XSDataResultControlDozor.setPngPlots argument is not list but %s" % pngPlots.__class__.__name__ + raise BaseException(strMessage) + def delPngPlots(self): self._pngPlots = None + pngPlots = property(getPngPlots, setPngPlots, delPngPlots, "Property for pngPlots") + def addPngPlots(self, value): + if value is None: + strMessage = "ERROR! XSDataResultControlDozor.addPngPlots argument is None" + raise BaseException(strMessage) + elif value.__class__.__name__ == "XSDataFile": + self._pngPlots.append(value) + else: + strMessage = "ERROR! XSDataResultControlDozor.addPngPlots argument is not XSDataFile but %s" % value.__class__.__name__ + raise BaseException(strMessage) + def insertPngPlots(self, index, value): + if index is None: + strMessage = "ERROR! XSDataResultControlDozor.insertPngPlots argument 'index' is None" + raise BaseException(strMessage) + if value is None: + strMessage = "ERROR! XSDataResultControlDozor.insertPngPlots argument 'value' is None" + raise BaseException(strMessage) + elif value.__class__.__name__ == "XSDataFile": + self._pngPlots[index] = value + else: + strMessage = "ERROR! XSDataResultControlDozor.addPngPlots argument is not XSDataFile but %s" % value.__class__.__name__ + raise BaseException(strMessage) + def export(self, outfile, level, name_='XSDataResultControlDozor'): + showIndent(outfile, level) + outfile.write(unicode('<%s>\n' % name_)) + self.exportChildren(outfile, level + 1, name_) + showIndent(outfile, level) + outfile.write(unicode('\n' % name_)) + def exportChildren(self, outfile, level, name_='XSDataResultControlDozor'): + XSDataResult.exportChildren(self, outfile, level, name_) + for imageDozor_ in self.getImageDozor(): + imageDozor_.export(outfile, level, name_='imageDozor') + if self._inputDozor is not None: + self.inputDozor.export(outfile, level, name_='inputDozor') + if self._halfDoseTime is not None: + self.halfDoseTime.export(outfile, level, name_='halfDoseTime') + if self._dozorPlot is not None: + self.dozorPlot.export(outfile, level, name_='dozorPlot') + if self._pathToCbfDirectory is not None: + self.pathToCbfDirectory.export(outfile, level, name_='pathToCbfDirectory') + for pngPlots_ in self.getPngPlots(): + pngPlots_.export(outfile, level, name_='pngPlots') + def build(self, node_): + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'imageDozor': + obj_ = XSDataControlImageDozor() + obj_.build(child_) + self.imageDozor.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'inputDozor': + obj_ = XSDataDozorInput() + obj_.build(child_) + self.setInputDozor(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'halfDoseTime': + obj_ = XSDataDouble() + obj_.build(child_) + self.setHalfDoseTime(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'dozorPlot': + obj_ = XSDataFile() + obj_.build(child_) + self.setDozorPlot(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'pathToCbfDirectory': + obj_ = XSDataFile() + obj_.build(child_) + self.setPathToCbfDirectory(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'pngPlots': + obj_ = XSDataFile() + obj_.build(child_) + self.pngPlots.append(obj_) + XSDataResult.buildChildren(self, child_, nodeName_) + #Method for marshalling an object + def marshal( self ): + oStreamString = StringIO() + oStreamString.write(unicode('\n')) + self.export( oStreamString, 0, name_="XSDataResultControlDozor" ) + oStringXML = oStreamString.getvalue() + oStreamString.close() + return oStringXML + #Only to export the entire XML tree to a file stream on disk + def exportToFile( self, _outfileName ): + outfile = open( _outfileName, "w" ) + outfile.write(unicode('\n')) + self.export( outfile, 0, name_='XSDataResultControlDozor' ) + outfile.close() + #Deprecated method, replaced by exportToFile + def outputFile( self, _outfileName ): + print("WARNING: Method outputFile in class XSDataResultControlDozor is deprecated, please use instead exportToFile!") + self.exportToFile(_outfileName) + #Method for making a copy in a new instance + def copy( self ): + return XSDataResultControlDozor.parseString(self.marshal()) + #Static method for parsing a string + def parseString( _inString ): + doc = minidom.parseString(_inString) + rootNode = doc.documentElement + rootObj = XSDataResultControlDozor() + rootObj.build(rootNode) + # Check that all minOccurs are obeyed by marshalling the created object + oStreamString = StringIO() + rootObj.export( oStreamString, 0, name_="XSDataResultControlDozor" ) + oStreamString.close() + return rootObj + parseString = staticmethod( parseString ) + #Static method for parsing a file + def parseFile( _inFilePath ): + doc = minidom.parse(_inFilePath) + rootNode = doc.documentElement + rootObj = XSDataResultControlDozor() + rootObj.build(rootNode) + return rootObj + parseFile = staticmethod( parseFile ) +# end class XSDataResultControlDozor + + + +# End of data representation classes. + + diff --git a/mxcubecore/HardwareObjects/ALBA/XalocXSDataControlXia2DIALSv1_0.py b/mxcubecore/HardwareObjects/ALBA/XalocXSDataControlXia2DIALSv1_0.py new file mode 100644 index 0000000000..15b6da131d --- /dev/null +++ b/mxcubecore/HardwareObjects/ALBA/XalocXSDataControlXia2DIALSv1_0.py @@ -0,0 +1,599 @@ +#!/usr/bin/env python + +# +# Generated Mon Feb 5 08:54::10 2018 by EDGenerateDS. +# + +import os, sys +from xml.dom import minidom +from xml.dom import Node + + +strEdnaHome = os.environ.get("EDNA_HOME", None) + +dictLocation = { \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ + "XSDataCommon": "kernel/datamodel", \ +} + +try: + from XSDataCommon import XSDataBoolean + from XSDataCommon import XSDataFile + from XSDataCommon import XSDataInput + from XSDataCommon import XSDataInteger + from XSDataCommon import XSDataResult + from XSDataCommon import XSDataString +except ImportError as error: + if strEdnaHome is not None: + for strXsdName in dictLocation: + strXsdModule = strXsdName + ".py" + strRootdir = os.path.dirname(os.path.abspath(os.path.join(strEdnaHome, dictLocation[strXsdName]))) + for strRoot, listDirs, listFiles in os.walk(strRootdir): + if strXsdModule in listFiles: + sys.path.append(strRoot) + else: + raise error +from XSDataCommon import XSDataBoolean +from XSDataCommon import XSDataFile +from XSDataCommon import XSDataInput +from XSDataCommon import XSDataInteger +from XSDataCommon import XSDataResult +from XSDataCommon import XSDataString + + + + +# +# Support/utility functions. +# + +# Compabiltity between Python 2 and 3: +if sys.version.startswith('3'): + unicode = str + from io import StringIO +else: + from StringIO import StringIO + + +def showIndent(outfile, level): + for idx in range(level): + outfile.write(unicode(' ')) + + +def warnEmptyAttribute(_strName, _strTypeName): + pass + #if not _strTypeName in ["float", "double", "string", "boolean", "integer"]: + # print("Warning! Non-optional attribute %s of type %s is None!" % (_strName, _strTypeName)) + +class MixedContainer(object): + # Constants for category: + CategoryNone = 0 + CategoryText = 1 + CategorySimple = 2 + CategoryComplex = 3 + # Constants for content_type: + TypeNone = 0 + TypeText = 1 + TypeString = 2 + TypeInteger = 3 + TypeFloat = 4 + TypeDecimal = 5 + TypeDouble = 6 + TypeBoolean = 7 + def __init__(self, category, content_type, name, value): + self.category = category + self.content_type = content_type + self.name = name + self.value = value + def getCategory(self): + return self.category + def getContenttype(self, content_type): + return self.content_type + def getValue(self): + return self.value + def getName(self): + return self.name + def export(self, outfile, level, name): + if self.category == MixedContainer.CategoryText: + outfile.write(self.value) + elif self.category == MixedContainer.CategorySimple: + self.exportSimple(outfile, level, name) + else: # category == MixedContainer.CategoryComplex + self.value.export(outfile, level, name) + def exportSimple(self, outfile, level, name): + if self.content_type == MixedContainer.TypeString: + outfile.write(unicode('<%s>%s' % (self.name, self.value, self.name))) + elif self.content_type == MixedContainer.TypeInteger or \ + self.content_type == MixedContainer.TypeBoolean: + outfile.write(unicode('<%s>%d' % (self.name, self.value, self.name))) + elif self.content_type == MixedContainer.TypeFloat or \ + self.content_type == MixedContainer.TypeDecimal: + outfile.write(unicode('<%s>%f' % (self.name, self.value, self.name))) + elif self.content_type == MixedContainer.TypeDouble: + outfile.write(unicode('<%s>%g' % (self.name, self.value, self.name))) + +# +# Data representation classes. +# + + + +class XalocXSDataInputXia2DIALS(XSDataInput): + def __init__(self, + configuration=None, + cell=None, + symm=None, + doAnomAndNonanom=None, + processDirectory=None, + toN=None, + fromN=None, + templateN=None, + dirN=None, + dataCollectionId=None, + diffractionImage = None, + small_molecule_3dii = None, + detector_max_res=None + ): + XSDataInput.__init__(self, configuration) + if dataCollectionId is None: + self._dataCollectionId = None + elif dataCollectionId.__class__.__name__ == "XSDataInteger": + self._dataCollectionId = dataCollectionId + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS constructor argument 'dataCollectionId' is not XSDataInteger but %s" % self._dataCollectionId.__class__.__name__ + raise BaseException(strMessage) + if diffractionImage is None: + self._diffractionImage = None + elif diffractionImage.__class__.__name__ == "XSDataBoolean": + self._diffractionImage = diffractionImage + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'diffractionImage' is not XSDataBoolean but %s" % diffractionImage.__class__.__name__ + raise BaseException(strMessage) + if dirN is None: + self._dirN = None + elif dirN.__class__.__name__ == "XSDataFile": + self._dirN = dirN + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS constructor argument 'dirN' is not XSDataFile but %s" % self._dirN.__class__.__name__ + raise BaseException(strMessage) + if templateN is None: + self._templateN = None + elif templateN.__class__.__name__ == "XSDataString": + self._templateN = templateN + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS constructor argument 'templateN' is not XSDataString but %s" % self._templateN.__class__.__name__ + raise BaseException(strMessage) + if fromN is None: + self._fromN = None + elif fromN.__class__.__name__ == "XSDataInteger": + self._fromN = fromN + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS constructor argument 'fromN' is not XSDataInteger but %s" % self._fromN.__class__.__name__ + raise BaseException(strMessage) + if toN is None: + self._toN = None + elif toN.__class__.__name__ == "XSDataInteger": + self._toN = toN + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS constructor argument 'toN' is not XSDataInteger but %s" % self._toN.__class__.__name__ + raise BaseException(strMessage) + if processDirectory is None: + self._processDirectory = None + elif processDirectory.__class__.__name__ == "XSDataFile": + self._processDirectory = processDirectory + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS constructor argument 'processDirectory' is not XSDataFile but %s" % self._processDirectory.__class__.__name__ + raise BaseException(strMessage) + if doAnomAndNonanom is None: + self._doAnomAndNonanom = None + elif doAnomAndNonanom.__class__.__name__ == "XSDataBoolean": + self._doAnomAndNonanom = doAnomAndNonanom + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS constructor argument 'doAnomAndNonanom' is not XSDataBoolean but %s" % self._doAnomAndNonanom.__class__.__name__ + raise BaseException(strMessage) + if symm is None: + self._symm = None + elif symm.__class__.__name__ == "XSDataString": + self._symm = symm + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS constructor argument 'symm' is not XSDataString but %s" % self._symm.__class__.__name__ + raise BaseException(strMessage) + if cell is None: + self._cell = None + elif cell.__class__.__name__ == "XSDataString": + self._cell = cell + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS constructor argument 'cell' is not XSDataString but %s" % self._cell.__class__.__name__ + raise BaseException(strMessage) + if small_molecule_3dii is None: + self._small_molecule_3dii = None + elif small_molecule_3dii.__class__.__name__ == "XSDataBoolean": + self._small_molecule_3dii = small_molecule_3dii + else: + strMessage = "ERROR! XSDataInputControlAutoPROC constructor argument 'small_molecule_3dii' is not XSDataBoolean but %s" % small_molecule_3dii.__class__.__name__ + raise BaseException(strMessage) + if detector_max_res is None: + self._detector_max_res = None + elif detector_max_res.__class__.__name__ == "XSDataDouble": + self._detector_max_res = detector_max_res + else: + strMessage = ( + "ERROR! XSDataAutoprocInput constructor argument 'detector_max_res' is not XSDataDouble but %s" + % self._detector_max_res.__class__.__name__ + ) + raise Exception(strMessage) + + + # Methods and properties for the 'small_molecule_3dii' attribute, used for xia2 small molecule processing + def get_small_molecule_3dii(self): return self._small_molecule_3dii + def set_small_molecule_3dii(self, small_molecule_3dii): + if small_molecule_3dii is None: + self._small_molecule_3dii = None + elif small_molecule_3dii.__class__.__name__ == "XSDataBoolean": + self._small_molecule_3dii = small_molecule_3dii + else: + strMessage = "ERROR! XSDataInputControlAutoPROC.set_small_molecule_3dii argument is not XSDataBoolean but %s" % small_molecule_3dii.__class__.__name__ + raise BaseException(strMessage) + def del_small_molecule_3dii(self): self._small_molecule_3dii = None + + # Methods and properties for the 'dataCollectionId' attribute + def getDataCollectionId(self): return self._dataCollectionId + def setDataCollectionId(self, dataCollectionId): + if dataCollectionId is None: + self._dataCollectionId = None + elif dataCollectionId.__class__.__name__ == "XSDataInteger": + self._dataCollectionId = dataCollectionId + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS.setDataCollectionId argument is not XSDataInteger but %s" % dataCollectionId.__class__.__name__ + raise BaseException(strMessage) + def delDataCollectionId(self): self._dataCollectionId = None + dataCollectionId = property(getDataCollectionId, setDataCollectionId, delDataCollectionId, "Property for dataCollectionId") + # Methods and properties for the 'image' attribute + def getDiffractionImage(self): return self._diffractionImage + def setDiffractionImage(self, image): + if image is None: + self._diffractionImage = None + elif image.__class__.__name__ == "XSDataString": + self._diffractionImage = image + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS.setDiffractionImage argument is not XSDataString but %s" % image.__class__.__name__ + raise BaseException(strMessage) + def delDiffractionImage(self): self._diffractionImage = None + diffractionImage = property(getDiffractionImage, setDiffractionImage, delDiffractionImage, "Property for diffractionImage") + # Methods and properties for the 'dirN' attribute + def getDirN(self): return self._dirN + def setDirN(self, dirN): + if dirN is None: + self._dirN = None + elif dirN.__class__.__name__ == "XSDataFile": + self._dirN = dirN + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS.setDirN argument is not XSDataFile but %s" % dirN.__class__.__name__ + raise BaseException(strMessage) + def delDirN(self): self._dirN = None + dirN = property(getDirN, setDirN, delDirN, "Property for dirN") + # Methods and properties for the 'templateN' attribute + def getTemplateN(self): return self._templateN + def setTemplateN(self, templateN): + if templateN is None: + self._templateN = None + elif templateN.__class__.__name__ == "XSDataString": + self._templateN = templateN + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS.setTemplateN argument is not XSDataString but %s" % templateN.__class__.__name__ + raise BaseException(strMessage) + def delTemplateN(self): self._templateN = None + templateN = property(getTemplateN, setTemplateN, delTemplateN, "Property for templateN") + # Methods and properties for the 'fromN' attribute + def getFromN(self): return self._fromN + def setFromN(self, fromN): + if fromN is None: + self._fromN = None + elif fromN.__class__.__name__ == "XSDataInteger": + self._fromN = fromN + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS.setFromN argument is not XSDataInteger but %s" % fromN.__class__.__name__ + raise BaseException(strMessage) + def delFromN(self): self._fromN = None + fromN = property(getFromN, setFromN, delFromN, "Property for fromN") + # Methods and properties for the 'toN' attribute + def getToN(self): return self._toN + def setToN(self, toN): + if toN is None: + self._toN = None + elif toN.__class__.__name__ == "XSDataInteger": + self._toN = toN + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS.setToN argument is not XSDataInteger but %s" % toN.__class__.__name__ + raise BaseException(strMessage) + def delToN(self): self._toN = None + toN = property(getToN, setToN, delToN, "Property for toN") + # Methods and properties for the 'processDirectory' attribute + def getProcessDirectory(self): return self._processDirectory + def setProcessDirectory(self, processDirectory): + if processDirectory is None: + self._processDirectory = None + elif processDirectory.__class__.__name__ == "XSDataFile": + self._processDirectory = processDirectory + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS.setProcessDirectory argument is not XSDataFile but %s" % processDirectory.__class__.__name__ + raise BaseException(strMessage) + def delProcessDirectory(self): self._processDirectory = None + processDirectory = property(getProcessDirectory, setProcessDirectory, delProcessDirectory, "Property for processDirectory") + # Methods and properties for the 'doAnomAndNonanom' attribute + def getDoAnomAndNonanom(self): return self._doAnomAndNonanom + def setDoAnomAndNonanom(self, doAnomAndNonanom): + if doAnomAndNonanom is None: + self._doAnomAndNonanom = None + elif doAnomAndNonanom.__class__.__name__ == "XSDataBoolean": + self._doAnomAndNonanom = doAnomAndNonanom + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS.setDoAnomAndNonanom argument is not XSDataBoolean but %s" % doAnomAndNonanom.__class__.__name__ + raise BaseException(strMessage) + def delDoAnomAndNonanom(self): self._doAnomAndNonanom = None + doAnomAndNonanom = property(getDoAnomAndNonanom, setDoAnomAndNonanom, delDoAnomAndNonanom, "Property for doAnomAndNonanom") + # Methods and properties for the 'symm' attribute + def getSpacegroup(self): return self._symm + def setSpacegroup(self, symm): + if symm is None: + self._symm = None + elif symm.__class__.__name__ == "XSDataString": + self._symm = symm + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS.setSymm argument is not XSDataString but %s" % symm.__class__.__name__ + raise BaseException(strMessage) + def delSpacegroup(self): self._symm = None + symm = property(getSpacegroup, setSpacegroup, delSpacegroup, "Property for symm") + # Methods and properties for the 'cell' attribute + def getUnit_cell(self): return self._cell + def setUnit_cell(self, cell): + if cell is None: + self._cell = None + elif cell.__class__.__name__ == "XSDataString": + self._cell = cell + else: + strMessage = "ERROR! XalocXSDataInputXia2DIALS.setCell argument is not XSDataString but %s" % cell.__class__.__name__ + raise BaseException(strMessage) + def delUnit_cell(self): self._cell = None + unit_cell = property(getUnit_cell, setUnit_cell, delUnit_cell, "Property for cell") + # Methods and properties for the 'detector_max_res' attribute + + def getDetector_max_res(self): + return self._detector_max_res + + def setDetector_max_res(self, detector_max_res): + if detector_max_res is None: + self._detector_max_res = None + elif detector_max_res.__class__.__name__ == "XSDataDouble": + self._detector_max_res = detector_max_res + else: + strMessage = ( + "ERROR! XSDataAutoprocInput.setDetector_max_res argument is not XSDataDouble but %s" + % detector_max_res.__class__.__name__ + ) + raise Exception(strMessage) + + def delDetector_max_res(self): + self._detector_max_res = None + + detector_max_res = property( + getDetector_max_res, + setDetector_max_res, + delDetector_max_res, + "Property for detector_max_res", + ) + + def export(self, outfile, level, name_='XSDataInputXIA2'): + showIndent(outfile, level) + outfile.write(unicode('<%s>\n' % name_)) + self.exportChildren(outfile, level + 1, name_) + showIndent(outfile, level) + outfile.write(unicode('\n' % name_)) + def exportChildren(self, outfile, level, name_='XSDataInputXIA2'): + XSDataInput.exportChildren(self, outfile, level, name_) + if self._dataCollectionId is not None: + self.dataCollectionId.export(outfile, level, name_='dataCollectionId') + #self.dataCollectionId.export(outfile, level, name_='data_collection_id') + if self._dirN is not None: + self.dirN.export(outfile, level, name_='dirN') + if self._templateN is not None: + self.templateN.export(outfile, level, name_='templateN') + if self._fromN is not None: + self.fromN.export(outfile, level, name_='startFrame') + if self._toN is not None: + self.toN.export(outfile, level, name_='endFrame') + if self._processDirectory is not None: + self.processDirectory.export(outfile, level, name_='processDirectory') + if self._doAnomAndNonanom is not None: + self.doAnomAndNonanom.export(outfile, level, name_='doAnomAndNonanom') + if self._symm is not None: + self.symm.export(outfile, level, name_='spaceGroup') + if self._cell is not None: + self._cell.export(outfile, level, name_='cell') + if self._small_molecule_3dii is not None: + self._small_molecule_3dii.export(outfile, level, name_='smallMolecule3dii') + #TODO: implement this properly using children + if self._diffractionImage is not None: + showIndent(outfile, level) + outfile.write(unicode('\n')) + self._diffractionImage.export(outfile, level+1, name_='path') + showIndent(outfile, level) + outfile.write(unicode('\n')) + if self._detector_max_res is not None: + self._detector_max_res.export(outfile, level, name_="d_min") + def build(self, node_): + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'dataCollectionId': + obj_ = XSDataInteger() + obj_.build(child_) + self.setDataCollectionId(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'dirN': + obj_ = XSDataFile() + obj_.build(child_) + self.setDirN(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'configDef': + obj_ = XSDataFile() + obj_.build(child_) + self.setConfigDef(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'templateN': + obj_ = XSDataString() + obj_.build(child_) + self.setTemplateN(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'fromN': + obj_ = XSDataInteger() + obj_.build(child_) + self.setFromN(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'toN': + obj_ = XSDataInteger() + obj_.build(child_) + self.setToN(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'processDirectory': + obj_ = XSDataFile() + obj_.build(child_) + self.setProcessDirectory(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'doAnomAndNonanom': + obj_ = XSDataBoolean() + obj_.build(child_) + self.setDoAnomAndNonanom(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'symm': + obj_ = XSDataString() + obj_.build(child_) + self.setSymm(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'cell': + obj_ = XSDataString() + obj_.build(child_) + self.setCell(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'detector_max_res': + obj_ = XSDataDouble() + obj_.build(child_) + self.setDetector_max_res(obj_) + + XSDataInput.buildChildren(self, child_, nodeName_) + #Method for marshalling an object + def marshal( self ): + oStreamString = StringIO() + oStreamString.write(unicode('\n')) + self.export( oStreamString, 0, name_="XSDataInputXIA2" ) + oStringXML = oStreamString.getvalue() + oStreamString.close() + return oStringXML + #Only to export the entire XML tree to a file stream on disk + def exportToFile( self, _outfileName ): + outfile = open( _outfileName, "w" ) + outfile.write(unicode('\n')) + self.export( outfile, 0, name_='XSDataInputXIA2' ) + outfile.close() + #Deprecated method, replaced by exportToFile + def outputFile( self, _outfileName ): + print("WARNING: Method outputFile in class XalocXSDataInputXia2DIALS is deprecated, please use instead exportToFile!") + self.exportToFile(_outfileName) + #Method for making a copy in a new instance + def copy( self ): + return XalocXSDataInputXia2DIALS.parseString(self.marshal()) + #Static method for parsing a string + def parseString( _inString ): + doc = minidom.parseString(_inString) + rootNode = doc.documentElement + rootObj = XalocXSDataInputXia2DIALS() + rootObj.build(rootNode) + # Check that all minOccurs are obeyed by marshalling the created object + oStreamString = StringIO() + rootObj.export( oStreamString, 0, name_="XSDataInputXIA2" ) + oStreamString.close() + return rootObj + parseString = staticmethod( parseString ) + #Static method for parsing a file + def parseFile( _inFilePath ): + doc = minidom.parse(_inFilePath) + rootNode = doc.documentElement + rootObj = XalocXSDataInputXia2DIALS() + rootObj.build(rootNode) + return rootObj + parseFile = staticmethod( parseFile ) +# end class XalocXSDataInputXia2DIALS + + +class XSDataResultControlAutoPROC(XSDataResult): + def __init__(self, status=None): + XSDataResult.__init__(self, status) + def export(self, outfile, level, name_='XSDataResultControlAutoPROC'): + showIndent(outfile, level) + outfile.write(unicode('<%s>\n' % name_)) + self.exportChildren(outfile, level + 1, name_) + showIndent(outfile, level) + outfile.write(unicode('\n' % name_)) + def exportChildren(self, outfile, level, name_='XSDataResultControlAutoPROC'): + XSDataResult.exportChildren(self, outfile, level, name_) + def build(self, node_): + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildChildren(self, child_, nodeName_): + pass + XSDataResult.buildChildren(self, child_, nodeName_) + #Method for marshalling an object + def marshal( self ): + oStreamString = StringIO() + oStreamString.write(unicode('\n')) + self.export( oStreamString, 0, name_="XSDataResultControlAutoPROC" ) + oStringXML = oStreamString.getvalue() + oStreamString.close() + return oStringXML + #Only to export the entire XML tree to a file stream on disk + def exportToFile( self, _outfileName ): + outfile = open( _outfileName, "w" ) + outfile.write(unicode('\n')) + self.export( outfile, 0, name_='XSDataResultControlAutoPROC' ) + outfile.close() + #Deprecated method, replaced by exportToFile + def outputFile( self, _outfileName ): + print("WARNING: Method outputFile in class XSDataResultControlAutoPROC is deprecated, please use instead exportToFile!") + self.exportToFile(_outfileName) + #Method for making a copy in a new instance + def copy( self ): + return XSDataResultControlAutoPROC.parseString(self.marshal()) + #Static method for parsing a string + def parseString( _inString ): + doc = minidom.parseString(_inString) + rootNode = doc.documentElement + rootObj = XSDataResultControlAutoPROC() + rootObj.build(rootNode) + # Check that all minOccurs are obeyed by marshalling the created object + oStreamString = StringIO() + rootObj.export( oStreamString, 0, name_="XSDataResultControlAutoPROC" ) + oStreamString.close() + return rootObj + parseString = staticmethod( parseString ) + #Static method for parsing a file + def parseFile( _inFilePath ): + doc = minidom.parse(_inFilePath) + rootNode = doc.documentElement + rootObj = XSDataResultControlAutoPROC() + rootObj.build(rootNode) + return rootObj + parseFile = staticmethod( parseFile ) +# end class XSDataResultControlAutoPROC + + + +# End of data representation classes. + + diff --git a/mxcubecore/HardwareObjects/BeamInfo.py b/mxcubecore/HardwareObjects/BeamInfo.py index c4f3bb94a6..725bcf5bf9 100644 --- a/mxcubecore/HardwareObjects/BeamInfo.py +++ b/mxcubecore/HardwareObjects/BeamInfo.py @@ -22,9 +22,10 @@ import logging from mxcubecore.BaseHardwareObjects import Equipment from mxcubecore import HardwareRepository as HWR +from mxcubecore.HardwareObjects.abstract.AbstractBeam import AbstractBeam -class BeamInfo(Equipment): +class BeamInfo(AbstractBeam): """ Description: """ @@ -33,7 +34,7 @@ def __init__(self, *args): """ Descrip. : """ - Equipment.__init__(self, *args) + AbstractBeam.__init__(self, *args) self.aperture_hwobj = None self.beam_definer = None @@ -53,6 +54,7 @@ def init(self): """ Descript. : """ + AbstractBeam.init(self) self.beam_size_slits = [9999, 9999] self.beam_size_aperture = [9999, 9999] self.beam_size_definer = [9999, 9999] @@ -205,11 +207,13 @@ def evaluate_beam_info(self): Return : dictionary,{size_x:0.1, size_y:0.1, shape:"rectangular"} """ size_x = min( + self.beam_info_dict["size_x"], self.beam_size_aperture[0], self.beam_size_slits[0], self.beam_size_definer[0], ) size_y = min( + self.beam_info_dict["size_y"], self.beam_size_aperture[1], self.beam_size_slits[1], self.beam_size_definer[1], diff --git a/mxcubecore/HardwareObjects/Beamline.py b/mxcubecore/HardwareObjects/Beamline.py index b3c173835d..4e6e8c07a9 100644 --- a/mxcubecore/HardwareObjects/Beamline.py +++ b/mxcubecore/HardwareObjects/Beamline.py @@ -198,6 +198,17 @@ def flux(self): __content_roles.append("flux") + @property + def digital_zoom(self): + """Flux Hardware object + + Returns: + Optional[AbstractActuator]: + """ + return self._objects.get("digital_zoom") + + __content_roles.append("digital_zoom") + @property def beam(self): """Beam Hardware object @@ -554,6 +565,29 @@ def image_tracking(self): __content_roles.append("image_tracking") + @property + def supervisor(self): + """Imaging tracking object + + Returns: + Optional[HardwareObject]: + """ + return self._objects.get("supervisor") + + __content_roles.append("supervisor") + + @property + def ln2shower(self): + """Imaging tracking object + + Returns: + Optional[HardwareObject]: + """ + return self._objects.get("ln2shower") + + __content_roles.append("ln2shower") + + # Procedures @property diff --git a/mxcubecore/HardwareObjects/Cats90.py b/mxcubecore/HardwareObjects/Cats90.py index 5587098aa6..4160c24220 100644 --- a/mxcubecore/HardwareObjects/Cats90.py +++ b/mxcubecore/HardwareObjects/Cats90.py @@ -184,8 +184,14 @@ def init(self): # add support for CATS dewars with variable number of lids # Create channels from XML - - self.cats_device = PyTango.DeviceProxy(self.get_property("tangoname")) + try: + cats_name = self.get_property("tangoname") + except AttributeError as e: + logging.getLogger("HWR").debug( + "cats device not under tangoname, trying taurusname" + ) + cats_name = self.get_property("taurusname") + self.cats_device = PyTango.DeviceProxy( self.get_property("taurusname") ) no_of_lids = self.get_property("no_of_lids") if no_of_lids is None: @@ -418,8 +424,11 @@ def init(self): try: self.basket_types = self.cats_device.read_attribute("CassetteType").value self.number_of_baskets = len(self.basket_types) - except PyTango.DevFailed: - pass + except PyTango.DevFailed as e: + logging.getLogger("HWR").warning( + "Device failed with error %s" % (e) + ) + #pass # find number of baskets and number of samples per basket if self.number_of_baskets is not None: @@ -588,7 +597,7 @@ def _init_sc_contents(self): datamatrix = None present = scanned = loaded = _has_been_loaded = False sample._set_info(present, datamatrix, scanned) - sample._set_loaded(loaded, has_been_loaded) + sample._set_loaded(loaded, _has_been_loaded) sample._set_holder_length(spl[4]) logging.getLogger("HWR").warning("Cats90: initializing contents done") @@ -643,7 +652,7 @@ def _do_update_info(self): :rtype: None """ logging.info( - "doUpdateInfo should not be called for cats. only for update timer type of SC" + "do_update_info should not be called for cats. only for update timer type of SC" ) return @@ -658,6 +667,7 @@ def _do_change_mode(self, mode): :returns: None :rtype: None """ + pass def _directly_update_selected_component(self, basket_no, sample_no): basket = None @@ -861,7 +871,7 @@ def _do_load(self, sample=None, shifts=None): else: if self.cats_sample_on_diffr() == 1: logging.getLogger("HWR").warning( - " ==========CATS=== trying to load sample, but sample detected on diffr. aborting" + " ==========CATS=== trying to load sample, but there is an unknown sample detected on diffr. aborting" ) self._update_state() # remove software flags like Loading. elif self.cats_sample_on_diffr() == -1: @@ -967,9 +977,9 @@ def cats_state_changed(self, value): while value in [PyTango.DevState.ALARM, PyTango.DevState.ON]: time.sleep(0.1) trials += 1 - logging.getLogger("HWR").warning( - "SAMPLE CHANGER could be in transient state. trying again" - ) + #logging.getLogger("HWR").warning( + #"SAMPLE CHANGER could be in transient state. trying again" + #) value = self._chnState.get_value() if trials > 4: break @@ -1010,7 +1020,7 @@ def cats_basket_presence_changed(self, value): if presence != self.basket_presence: logging.getLogger("HWR").warning( - "Basket presence changed. Updating contents" + "cats_basket_presence_changed Basket presence changed. Updating contents" ) self.basket_presence = presence self._update_cats_contents() @@ -1206,10 +1216,10 @@ def _decide_state(self, dev_state, powered, lids_closed, has_loaded, on_diff): elif has_loaded ^ on_diff: # go to Unknown state if a sample is detected on the gonio but not registered in the internal database # or registered but not on the gonio anymore - logging.getLogger("HWR").warning( - "SAMPLE CHANGER Unknown 2 (hasLoaded: %s / detected: %s)" - % (self.has_loaded_sample(), self._chnSampleIsDetected.get_value()) - ) + #logging.getLogger("HWR").warning( + #"SAMPLE CHANGER Unknown 2 (hasLoaded: %s / detected: %s)" + #% (self.has_loaded_sample(), self._chnSampleIsDetected.get_value()) + #) _state = SampleChangerState.Unknown # elif not lids_closed: # _state = SampleChangerState.Charging @@ -1376,14 +1386,22 @@ def _update_loaded_sample(self, sample_num=None, lid=None): old_sample = self.get_loaded_sample() + old_address = None + if old_sample != None: + old_address = old_sample.get_address() + new_address = None + if new_sample != None: + new_address = new_sample.get_address() logging.getLogger("HWR").debug( "----- Cats90 -----. Sample has changed. Dealing with it - new_sample = %s / old_sample = %s" - % (new_sample, old_sample) + % ( old_address, new_address ) ) if old_sample != new_sample: # remove 'loaded' flag from old sample but keep all other information + #TODO: send a signal to be captured by the tree_brick so that the tree can be updated with the new sample info + if old_sample is not None: # there was a sample on the gonio loaded = False @@ -1398,7 +1416,7 @@ def _update_loaded_sample(self, sample_num=None, lid=None): if ( (old_sample is None) or (new_sample is None) - or (old_sample.get_address() != new_loaded.get_address()) + or (old_sample.get_address() != new_sample.get_address()) ): self._trigger_loaded_sample_changed_event(new_sample) self._trigger_info_changed_event() @@ -1444,7 +1462,7 @@ def _do_update_cats_contents(self): def _update_cats_contents(self): logging.getLogger("HWR").warning( - "Updating contents %s" % str(self.basket_presence) + "_update_cats_contents Updating contents %s" % str(self.basket_presence) ) for basket_index in range(self.number_of_baskets): # get saved presence information from object's internal bookkeeping @@ -1485,7 +1503,7 @@ def _update_cats_contents(self): # forget about any loaded state in newly mounted or removed basket) loaded = _has_been_loaded = False - sample._set_loaded(loaded, has_been_loaded) + sample._set_loaded(loaded, _has_been_loaded) self._trigger_contents_updated_event() self._update_loaded_sample() diff --git a/mxcubecore/HardwareObjects/CatsMaint.py b/mxcubecore/HardwareObjects/CatsMaint.py index 8439ec3869..02e93f41e8 100644 --- a/mxcubecore/HardwareObjects/CatsMaint.py +++ b/mxcubecore/HardwareObjects/CatsMaint.py @@ -487,7 +487,8 @@ def _do_set_on_diff(self, sample): # calculate CATS specific lid/sample number lid = (int(sample_tmp[0]) - 1) / 3 + 1 puc_pos = ((int(sample_tmp[0]) - 1) % 3) * 10 + int(sample_tmp[1]) - argin = [str(lid), str(puc_pos), "0"] + basket_types = self.cats_device.read_attribute("CassetteType").value + argin = [str(lid), str(puc_pos), str( basket_types[ sample_tmp[0]-1 ] ) ] logging.getLogger().info("to SetOnDiff %s", argin) self._execute_server_task(self._cmdSetOnDiff, argin) @@ -525,7 +526,6 @@ def _do_power_state(self, state=False): else: self._cmdPowerOff() - self.do_state_action("power", state) def _do_enable_regulation(self): """ diff --git a/mxcubecore/HardwareObjects/EDNACharacterisation.py b/mxcubecore/HardwareObjects/EDNACharacterisation.py index f806cb83c1..aea0e284e5 100644 --- a/mxcubecore/HardwareObjects/EDNACharacterisation.py +++ b/mxcubecore/HardwareObjects/EDNACharacterisation.py @@ -229,7 +229,7 @@ def input_from_params(self, data_collection, char_params): for img_num in range(int(acquisition_parameters.num_images)): image_file = XSDataFile() path = XSDataString() - path.set_value(path_str % (img_num + 1)) + path.setValue(path_str % (img_num + 1)) image_file.setPath(path) data_set.addImageFile(image_file) diff --git a/mxcubecore/HardwareObjects/GphlWorkflow.py b/mxcubecore/HardwareObjects/GphlWorkflow.py index 58ec04a0ba..287292c4ef 100644 --- a/mxcubecore/HardwareObjects/GphlWorkflow.py +++ b/mxcubecore/HardwareObjects/GphlWorkflow.py @@ -43,7 +43,7 @@ from mxcubecore.dispatcher import dispatcher from mxcubecore.utils import conversion -from mxcubecore.BaseHardwareObjects import HardwareObjectYaml +from mxcubecore.BaseHardwareObjects import HardwareObject from mxcubecore.HardwareObjects import queue_model_objects from mxcubecore.HardwareObjects import queue_model_enumerables from mxcubecore.HardwareObjects.queue_entry import QUEUE_ENTRY_STATUS @@ -75,7 +75,7 @@ ) -class GphlWorkflow(HardwareObjectYaml): +class GphlWorkflow(HardwareObject, object): """Global Phasing workflow runner. """ @@ -84,13 +84,16 @@ class GphlWorkflow(HardwareObjectYaml): def __init__(self, name): super(GphlWorkflow, self).__init__(name) + # HO that handles connection to GPhL workflow runner + self._workflow_connection = None + # Needed to allow methods to put new actions on the queue # And as a place to get hold of other objects self._queue_entry = None # Configuration data - set when queried - self.workflows = {} - self.settings = {} + #self.workflows = {} + #self.settings = {} # Current data collection task group. Different for characterisation and collection self._data_collection_group = None @@ -99,7 +102,7 @@ def __init__(self, name): self._return_parameters = None # Queue to read messages from GphlConnection - self._workflow_queue = None + #self._workflow_queue = None # Message - processing function map self._processor_functions = {} @@ -119,12 +122,27 @@ def __init__(self, name): # Configurable file paths self.file_paths = {} + # Dose budget pulldown labels and default + self.dose_budgets = OrderedDict() + self.default_dose_budget_label = None + + def _init(self): super(GphlWorkflow, self)._init() def init(self): super(GphlWorkflow, self).init() + # Get dose budget data + default_dose_budget_label = None + xx0 = next(self.get_objects("dose_budgets")) + for pulldown_item in xx0.get_objects("pulldown_item"): + dd0 = pulldown_item.get_properties() + self.dose_budgets[dd0["label"]] = float(dd0["value"]) + if default_dose_budget_label is None or dd0.get("is_default"): + default_dose_budget_label = dd0["label"] + self.default_dose_budget_label = default_dose_budget_label + # Set up processing functions map self._processor_functions = { "String": self.echo_info_string, @@ -141,7 +159,14 @@ def init(self): "WorkflowCompleted": self.workflow_completed, "WorkflowFailed": self.workflow_failed, } + + self.update_state(self.STATES.READY) + def setup_workflow_object(self): + """Necessary as this set-up cannot be done at init, + when the hwobj are still incomplete. Must be called externally + TODO This still necessary?""" + # Set standard configurable file paths file_paths = self.file_paths ss0 = HWR.beamline.gphl_connection.software_paths["gphl_beamline_config"] @@ -165,39 +190,37 @@ def init(self): (instrument_data["det_org_x"], instrument_data["det_org_y"]) ) - # Adapt configuration data - must be done after file_paths setting - if HWR.beamline.gphl_connection.ssh_options: - # We are running workflow through ssh - set beamline url - beamline_hook ="py4j:%s:" % socket.gethostname() - else: - beamline_hook = "py4j::" - - # Consolidate workflow options - for title, workflow in self.workflows.items(): - workflow["wfname"] = title - wftype = workflow["wftype"] - - opt0 = workflow.get("options", {}) - opt0["beamline"] = beamline_hook - default_strategy_name = None - for strategy in workflow["strategies"]: - strategy["wftype"] = wftype - if default_strategy_name is None: - default_strategy_name = workflow["strategy_name"] = ( - strategy["title"] - ) - dd0 = opt0.copy() - dd0.update(strategy.get("options", {})) - strategy["options"] = dd0 - if workflow["wftype"] == "transcal": - relative_file_path = strategy["options"].get("file") - if relative_file_path is not None: - # Special case - this option must be modified before use - strategy["options"]["file"] = os.path.join( - self.file_paths["gphl_beamline_config"], relative_file_path - ) - - self.update_state(self.STATES.READY) + ## Adapt configuration data - must be done after file_paths setting + #if HWR.beamline.gphl_connection.ssh_options: + ## We are running workflow through ssh - set beamline url + #beamline_hook ="py4j:%s:" % socket.gethostname() + #else: + #beamline_hook = "py4j::" + + ## Consolidate workflow options + #for title, workflow in self.workflows.items(): + #workflow["wfname"] = title + #wftype = workflow["wftype"] + + #opt0 = workflow.get("options", {}) + #opt0["beamline"] = beamline_hook + #default_strategy_name = None + #for strategy in workflow["strategies"]: + #strategy["wftype"] = wftype + #if default_strategy_name is None: + #default_strategy_name = workflow["strategy_name"] = ( + #strategy["title"] + #) + #dd0 = opt0.copy() + #dd0.update(strategy.get("options", {})) + #strategy["options"] = dd0 + #if workflow["wftype"] == "transcal": + #relative_file_path = strategy["options"].get("file") + #if relative_file_path is not None: + ## Special case - this option must be modified before use + #strategy["options"]["file"] = os.path.join( + #self.file_paths["gphl_beamline_config"], relative_file_path + #) def shutdown(self): """Shut down workflow and connection. Triggered on program quit.""" @@ -208,7 +231,96 @@ def shutdown(self): def get_available_workflows(self): """Get list of workflow description dictionaries.""" - return copy.deepcopy(self.workflows) + result = OrderedDict() + if self.has_object("workflow_properties"): + properties = self["workflow_properties"].get_properties().copy() + else: + properties = {} + if self.has_object("invocation_properties"): + invocation_properties = ( + self["invocation_properties"].get_properties().copy() + ) + else: + invocation_properties = {} + + if self.has_object("all_workflow_options"): + all_workflow_options = self["all_workflow_options"].get_properties().copy() + if "beamline" in all_workflow_options: + pass + elif HWR.beamline.gphl_connection.has_object("ssh_options"): + # We are running workflow through ssh - set beamline url + all_workflow_options["beamline"] = "py4j:%s:" % socket.gethostname() + else: + all_workflow_options["beamline"] = "py4j::" + else: + all_workflow_options = {} + + acq_workflow_options = all_workflow_options.copy() + acq_workflow_options.update(self["acq_workflow_options"].get_properties()) + # Add options for target directories: + process_root = HWR.beamline.session.get_base_process_directory() + acq_workflow_options["appdir"] = process_root + + mx_workflow_options = acq_workflow_options.copy() + mx_workflow_options.update(self["mx_workflow_options"].get_properties()) + + for wf_node in self["workflows"]: + name = wf_node.name() + strategy_type = wf_node.get_property("strategy_type") + wf_dict = { + "name": name, + "strategy_type": strategy_type, + "application": wf_node.get_property("application"), + "documentation": wf_node.get_property( + "documentation", default_value="" + ), + "interleaveOrder": wf_node.get_property( + "interleave_order", default_value="" + ), + } + result[name] = wf_dict + + if strategy_type.startswith("transcal"): + wf_dict["options"] = dd0 = all_workflow_options.copy() + if wf_node.has_object("options"): + dd0.update(wf_node["options"].get_properties()) + relative_file_path = dd0.get("file") + if relative_file_path is not None: + # Special case - this option must be modified before use + dd0["file"] = os.path.join( + self.file_paths["gphl_beamline_config"], relative_file_path + ) + + elif strategy_type.startswith("diffractcal"): + wf_dict["options"] = dd0 = acq_workflow_options.copy() + if wf_node.has_object("options"): + dd0.update(wf_node["options"].get_properties()) + + else: + wf_dict["options"] = dd0 = mx_workflow_options.copy() + if wf_node.has_object("options"): + dd0.update(wf_node["options"].get_properties()) + if wf_node.has_object("beam_energies"): + wf_dict["beam_energies"] = dd0 = OrderedDict() + for wavelength in wf_node["beam_energies"]: + dd0[wavelength.get_property("role")] = wavelength.get_property( + "value" + ) + + wf_dict["properties"] = dd0 = properties.copy() + if wf_node.has_object("properties"): + dd0.update(wf_node["properties"].get_properties()) + # Program-specific properties + devmode = dd0.get("co.gphl.wf.devMode") + if devmode and devmode[0] not in "fFnN": + # We are in developer mode. Add parameters + dd0["co.gphl.wf.stratcal.opt.--strategy_type"] = strategy_type + + wf_dict["invocation_properties"] = dd0 = invocation_properties.copy() + if wf_node.has_object("invocation_properties"): + dd0.update(wf_node["invocation_properties"].get_properties()) + # + return result def query_pre_strategy_params(self, data_model, choose_lattice=None): """ @@ -226,76 +338,54 @@ def query_pre_collection_params(self, data_model): def pre_execute(self, queue_entry): - if self.is_ready(): - self.update_state(self.STATES.BUSY) - else: - raise RuntimeError( - "Cannot execute workflow - GphlWorkflow HardwareObject is not ready" - ) self._queue_entry = queue_entry - data_model = queue_entry.get_data_model() - self._workflow_queue = gevent.queue.Queue() - HWR.beamline.gphl_connection.open_connection() - if data_model.automation_mode: - if data_model.get_workflow_parameters()["wftype"] == "acquisition": - params = data_model.auto_char_params - else: - params = data_model.auto_acq_params - else: - # SIGNAL TO GET Pre-strategy parameters here - # NB set defaults from data_model - # NB consider whether to override on None - params = self.query_pre_strategy_params(data_model) - data_model.set_pre_strategy_params(**params) - if data_model.detector_setting is None: - resolution = HWR.beamline.resolution.get_value() - distance = HWR.beamline.detector.distance.get_value() - orgxy = HWR.beamline.detector.get_beam_position() - data_model.detector_setting = GphlMessages.BcsDetectorSetting( - resolution, orgxy=orgxy, Distance=distance - ) - else: - # Set detector distance and resolution - distance = data_model.detector_setting.axisSettings["Distance"] - HWR.beamline.detector.distance.set_value(distance, timeout=30) - def execute(self): + if self.get_state() == self.STATES.OFF: + HWR.beamline.gphl_connection.open_connection() + self.update_state(self.STATES.READY) - if HWR.beamline.gphl_connection is None: - raise RuntimeError( - "Cannot execute workflow - GphlWorkflowConnection not found" - ) + def execute(self): - # Fork off workflow server process - HWR.beamline.gphl_connection.start_workflow( - self._workflow_queue, self._queue_entry.get_data_model() - ) + try: + self.update_state(self.STATES.BUSY) - while True: - if self._workflow_queue is None: - # We can only get that value if we have already done post_execute - # but the mechanics of aborting means we conme back - # Stop further processing here - raise QueueAbortedException("Aborting...", self) - - tt0 = self._workflow_queue.get() - if tt0 is StopIteration: - logging.getLogger("HWR").debug("GPhL queue StopIteration") - break - - message_type, payload, correlation_id, result_list = tt0 - func = self._processor_functions.get(message_type) - if func is None: - logging.getLogger("HWR").error( - "GPhL message %s not recognised by MXCuBE. Terminating...", - message_type, + workflow_queue = gevent._threading.Queue() + # Fork off workflow server process + if HWR.beamline.gphl_connection is not None: + HWR.beamline.gphl_connection.start_workflow( + workflow_queue, self._queue_entry.get_data_model() ) - break - elif message_type != "String": - logging.getLogger("HWR").info("GPhL queue processing %s", message_type) - response = func(payload, correlation_id) - if result_list is not None: - result_list.append((response, correlation_id)) + + while True: + while workflow_queue.empty(): + time.sleep(0.1) + + tt0 = workflow_queue.get_nowait() + if tt0 is StopIteration: + break + + message_type, payload, correlation_id, result_list = tt0 + func = self._processor_functions.get(message_type) + if func is None: + logging.getLogger("HWR").error( + "GPhL message %s not recognised by MXCuBE. Terminating...", + message_type, + ) + break + else: + logging.getLogger("HWR").info( + "GPhL queue processing %s", message_type + ) + response = func(payload, correlation_id) + if result_list is not None: + result_list.append((response, correlation_id)) + + except Exception: + self.workflow_end() + logging.getLogger("HWR").error( + "Uncaught error during GPhL workflow execution", exc_info=True + ) + raise def post_execute(self): """ diff --git a/mxcubecore/HardwareObjects/GphlWorkflowConnection.py b/mxcubecore/HardwareObjects/GphlWorkflowConnection.py index 90402db06a..dc838d35df 100644 --- a/mxcubecore/HardwareObjects/GphlWorkflowConnection.py +++ b/mxcubecore/HardwareObjects/GphlWorkflowConnection.py @@ -36,7 +36,7 @@ from mxcubecore.utils import conversion from mxcubecore.HardwareObjects.Gphl import GphlMessages -from mxcubecore.BaseHardwareObjects import HardwareObjectYaml +from mxcubecore.BaseHardwareObjects import HardwareObject from mxcubecore import HardwareRepository as HWR # NB this is patching the original socket module in to avoid the @@ -67,7 +67,7 @@ __author__ = "Rasmus H Fogh" -class GphlWorkflowConnection(HardwareObjectYaml): +class GphlWorkflowConnection(HardwareObject, object): """ This HO acts as a gateway to the Global Phasing workflow engine. """ @@ -95,6 +95,10 @@ def __init__(self, name): self.connection_parameters = {} self.software_paths = {} self.software_properties = {} + + # Properties for GPhL invocation + self.java_properties = {} + def _init(self): super(GphlWorkflowConnection, self)._init() @@ -109,27 +113,45 @@ def init(self): self.connection_parameters["python_address"] = socket.gethostname() # Adapt paths and properties to use directory_locations - locations = self.directory_locations - paths = self.software_paths - properties = self.software_properties + #locations = self.directory_locations + #paths = self.software_paths + #properties = self.software_properties + + if self.has_object("connection_parameters"): + self._connection_parameters.update( + self["connection_parameters"].get_properties() + ) + if self.has_object("ssh_options"): + # We are running through ssh - so we need python_address + # If not, we stick to default, which is localhost (127.0.0.1) + self._connection_parameters["python_address"] = socket.gethostname() - for tag, val in paths.items(): + locations = next(self.get_objects("directory_locations")).get_properties() + paths = self.software_paths + props = self.java_properties + dd0 = next(self.get_objects("software_paths")).get_properties() + + #for tag, val in paths.items(): + for tag, val in dd0.items(): val2 = val.format(**locations) if not os.path.isabs(val2): val2 = HWR.get_hardware_repository().find_in_repository(val) if val2 is None: raise ValueError("File path %s not recognised" % val) paths[tag] = val2 - - for tag, val in properties.items(): + dd0 = next(self.get_objects("software_properties")).get_properties() + #for tag, val in properties.items(): + for tag, val in dd0.items(): val2 = val.format(**locations) if not os.path.isabs(val2): val2 = HWR.get_hardware_repository().find_in_repository(val) if val2 is None: raise ValueError("File path %s not recognised" % val) - paths[tag] = properties[tag] = val2 + #paths[tag] = properties[tag] = val2 + paths[tag] = props[tag] = val2 - pp0 = properties["co.gphl.wf.bin"] = paths["GPHL_INSTALLATION"] + #pp0 = properties["co.gphl.wf.bin"] = paths["GPHL_INSTALLATION"] + pp0 = props["co.gphl.wf.bin"] = paths["GPHL_INSTALLATION"] paths["BDG_home"] = paths.get("co.gphl.wf.bdg_licence_dir") or pp0 self.update_state(self.STATES.OFF) diff --git a/mxcubecore/HardwareObjects/LdapLogin.py b/mxcubecore/HardwareObjects/LdapLogin.py index cfdc28354b..4ec2c1506d 100644 --- a/mxcubecore/HardwareObjects/LdapLogin.py +++ b/mxcubecore/HardwareObjects/LdapLogin.py @@ -139,7 +139,7 @@ def login(self, username, password, retry=True, fields=None): except ldap.LDAPError as err: if retry: self.cleanup(ex=err) - return self.login(username, password, retry=False) + return self.login(username, password, retry=False, fields=fields) else: return self.cleanup(ex=err) diff --git a/mxcubecore/HardwareObjects/QtGraphicsLib.py b/mxcubecore/HardwareObjects/QtGraphicsLib.py index 6ff1a38752..d38da2f53e 100644 --- a/mxcubecore/HardwareObjects/QtGraphicsLib.py +++ b/mxcubecore/HardwareObjects/QtGraphicsLib.py @@ -1005,7 +1005,7 @@ def set_corner_coord(self, corner_coord): self.__frame_polygon.setPoint(index, coord[0], coord[1]) if self.__overlay_pixmap: - if min(self.__spacing_pix) < 20: + if min(self.__spacing_pix) > 20: width = abs(corner_coord[0][0] - corner_coord[1][0]) height = abs(corner_coord[0][1] - corner_coord[3][1]) self.__overlay_pixmap.setPixmap( @@ -1015,6 +1015,7 @@ def set_corner_coord(self, corner_coord): self.__overlay_pixmap.setOpacity(self.__fill_alpha / 255.0) self.__overlay_pixmap.setPos(corner_coord[0][0], corner_coord[0][1]) else: + #logging.getLogger("HWR").debug("__overlay_pixmap not visible") self.__overlay_pixmap.setVisible(False) self.__grid_size_pix[0] = self.__spacing_pix[0] * self.__num_cols @@ -1039,7 +1040,7 @@ def set_overlay_pixmap(self, filename): self.__frame_polygon.point(0).x(), self.__frame_polygon.point(0).y() ) self.__overlay_pixmap.setOpacity(self.__fill_alpha / 255.0) - self.__overlay_pixmap.setVisible(min(self.__spacing_pix) < 20) + self.__overlay_pixmap.setVisible(min(self.__spacing_pix) > 20) def set_center_coord(self, center_coord): """ @@ -1058,6 +1059,7 @@ def set_spacing(self, spacing, adjust_size=False): :param adjust_size: boolean :return: """ + self.__spacing_mm[0] = spacing[0] self.__spacing_mm[1] = spacing[1] self.__spacing_pix[0] = self.pixels_per_mm[0] * self.__spacing_mm[0] diff --git a/mxcubecore/HardwareObjects/QtGraphicsManager.py b/mxcubecore/HardwareObjects/QtGraphicsManager.py index 708928954f..fd3a8f79e8 100644 --- a/mxcubecore/HardwareObjects/QtGraphicsManager.py +++ b/mxcubecore/HardwareObjects/QtGraphicsManager.py @@ -2035,7 +2035,7 @@ def select_lines_and_grids(self): for shape in self.shape_dict.values(): # for shape in self._shapes.get_all_shapes(): if isinstance(shape, GraphicsLib.GraphicsItemLine): - (start_point, end_point) = shape.get_graphics_points() + (start_point, end_point) = shape.get_graphical_points() if min( start_point.start_coord[0], end_point.start_coord[0] ) < select_middle_x < max( diff --git a/mxcubecore/HardwareObjects/QueueManager.py b/mxcubecore/HardwareObjects/QueueManager.py index 187d77bdb2..80c571345b 100644 --- a/mxcubecore/HardwareObjects/QueueManager.py +++ b/mxcubecore/HardwareObjects/QueueManager.py @@ -135,7 +135,10 @@ def __execute_task(self): qe.handle_exception(ex) self.stop() except gevent.GreenletExit: - pass + #pass + logging.getLogger("user_level_log").warning( + "Queue execution GreenletExit error, " + str(ex) + ) if isinstance(ex, base_queue_entry.QueueAbortedException): logging.getLogger("user_level_log").warning( @@ -146,6 +149,8 @@ def __execute_task(self): "Queue execution failed with: " + str(ex) ) + logging.getLogger("HWR").info( "traceback %s" % traceback.format_exc() ) + logging.getLogger("HWR").info( "ex %s" % ex ) raise ex finally: self._running = False diff --git a/mxcubecore/HardwareObjects/SardanaMotor.py b/mxcubecore/HardwareObjects/SardanaMotor.py index c760e57aeb..620225f96b 100644 --- a/mxcubecore/HardwareObjects/SardanaMotor.py +++ b/mxcubecore/HardwareObjects/SardanaMotor.py @@ -59,7 +59,7 @@ def __init__(self, name): self.limit_lower = None self.static_limits = (-1e4, 1e4) self.limits = (None, None) - self.motor_state = MotorStates.NOTINITIALIZED + self.motor_state = MotorStates.INITIALIZING def init(self): @@ -175,7 +175,7 @@ def motor_state_changed(self, state=None): if state is None: state = self.state_channel.get_value() - state = str(state) + state = str(state).strip("DevState.") motor_state = SardanaMotor.state_map[state] if motor_state != MotorStates.DISABLED: @@ -184,7 +184,6 @@ def motor_state_changed(self, state=None): elif self.motor_position <= self.limit_lower: motor_state = MotorStates.LOWLIMIT - self.set_ready(motor_state > MotorStates.DISABLED) if motor_state != self.motor_state: self.motor_state = motor_state @@ -216,6 +215,9 @@ def get_limits(self): static_limits is returned """ try: + info = self.position_channel.get_info() + self.limit_lower = info.minval + self.limit_upper = info.maxval return (self.limit_lower, self.limit_upper) except Exception: return (None, None) diff --git a/mxcubecore/HardwareObjects/SimpleHTML.py b/mxcubecore/HardwareObjects/SimpleHTML.py index 22dcab81f1..6d39834737 100644 --- a/mxcubecore/HardwareObjects/SimpleHTML.py +++ b/mxcubecore/HardwareObjects/SimpleHTML.py @@ -131,7 +131,7 @@ def create_json_images(image_list): return json_item -def generate_parallel_processing_report(mesh_scan_results, params_dict): +def generate_online_processing_report(mesh_scan_results, params_dict): json_dict = {"items": []} html_file = open(params_dict["html_file_path"], "w") @@ -144,7 +144,7 @@ def generate_parallel_processing_report(mesh_scan_results, params_dict): html_file.write(HTML_START % "Line scan results") json_dict["items"].append({"type": "title", "value": "Line scan results"}) - html_file.write(create_image("parallel_processing_plot.png")) + html_file.write(create_image("online_processing_plot.png")) html_file.write("
") html_file.write(create_text("Scan parameters", heading=1)) osc_range_per_line = params_dict["osc_range"] * (params_dict["images_per_line"] - 1) diff --git a/mxcubecore/HardwareObjects/XMLRPCServer.py b/mxcubecore/HardwareObjects/XMLRPCServer.py index 70375f314a..846847c664 100644 --- a/mxcubecore/HardwareObjects/XMLRPCServer.py +++ b/mxcubecore/HardwareObjects/XMLRPCServer.py @@ -169,7 +169,7 @@ def open(self): def anneal(self, time): cryoshutter_hwobj = self.get_object_by_role("cryoshutter") try: - cryoshutter_hwobj.getCommandObject("anneal")(time) + cryoshutter_hwobj.get_command_object("anneal")(time) except Exception as ex: logging.getLogger("HWR").exception(str(ex)) raise diff --git a/mxcubecore/HardwareObjects/abstract/AbstractCollect.py b/mxcubecore/HardwareObjects/abstract/AbstractCollect.py index f13880b8c7..5d33cebb7e 100644 --- a/mxcubecore/HardwareObjects/abstract/AbstractCollect.py +++ b/mxcubecore/HardwareObjects/abstract/AbstractCollect.py @@ -171,12 +171,22 @@ def do_collect(self, owner): "%Y-%m-%d %H:%M:%S" ) + log.info("Collection: Storing data collection in LIMS") + self.store_data_collection_in_lims() + logging.getLogger("HWR").info( "Collection parameters: %s" % str(self.current_dc_parameters) ) - log.info("Collection: Storing data collection in LIMS") - self.store_data_collection_in_lims() + if ( + self.current_dc_parameters['processing_online'] + and HWR.beamline.online_processing is not None + ): + HWR.beamline.online_processing.params_dict["collection_id"] = self.current_dc_parameters["collection_id"] + self.online_processing_task = gevent.spawn( + HWR.beamline.online_processing.run_processing, + self.current_dc_parameters + ) log.info( "Collection: Creating directories for raw images and processing files" @@ -610,7 +620,7 @@ def update_data_collection_in_lims(self): i += 1 params[ "resolutionAtCorner" - ] = HWR.beamline.resolution.get_value_at_corner() + ] = self.get_value_at_corner() beam_size_x, beam_size_y = HWR.beamline.beam.get_beam_size() params["beamSizeAtSampleX"] = beam_size_x params["beamSizeAtSampleY"] = beam_size_y @@ -833,6 +843,13 @@ def data_collection_hook(self): """ pass + @abc.abstractmethod + def get_value_at_corner(self): + """ + Descript. : + """ + pass + @abc.abstractmethod def trigger_auto_processing(self, process_event, frame_number): """ diff --git a/mxcubecore/HardwareObjects/abstract/AbstractMotor.py b/mxcubecore/HardwareObjects/abstract/AbstractMotor.py index 1147957769..0f1c21058d 100644 --- a/mxcubecore/HardwareObjects/abstract/AbstractMotor.py +++ b/mxcubecore/HardwareObjects/abstract/AbstractMotor.py @@ -40,11 +40,22 @@ class MotorStates(Enum): """Motor states definitions.""" - HOME = HardwareObjectState.READY, 5 - LOWLIMIT = HardwareObjectState.READY, 6 - HIGHLIMIT = HardwareObjectState.READY, 7 - MOVING = HardwareObjectState.BUSY, 8 + INITIALIZING = HardwareObjectState.BUSY, 0 + ON = HardwareObjectState.READY, 1 + OFF = HardwareObjectState.OFF, 2 + READY = HardwareObjectState.READY, 3 + BUSY = HardwareObjectState.BUSY, 4 + MOVING = HardwareObjectState.BUSY, 5 + STANDBY = HardwareObjectState.READY, 6 + DISABLED = HardwareObjectState.FAULT, 7 + UNKNOWN= HardwareObjectState.UNKNOWN, 8 + ALARM = HardwareObjectState.FAULT, 9 + FAULT = HardwareObjectState.FAULT, 10 + INVALID = HardwareObjectState.FAULT, 11 + OFFLINE = HardwareObjectState.OFF, 12 + LOWLIMIT = HardwareObjectState.READY, 13 + HIGHLIMIT = HardwareObjectState.READY, 14 class AbstractMotor(AbstractActuator): """Abstract motor class""" diff --git a/mxcubecore/HardwareObjects/abstract/AbstractSampleChanger.py b/mxcubecore/HardwareObjects/abstract/AbstractSampleChanger.py index 891ac82b77..f11d240889 100644 --- a/mxcubecore/HardwareObjects/abstract/AbstractSampleChanger.py +++ b/mxcubecore/HardwareObjects/abstract/AbstractSampleChanger.py @@ -253,10 +253,10 @@ def init(self): self.update_info() def _on_timer_1s_exit(self, task): - logging.warning("Exiting Sample Changer 1s timer task") + logging.getLogger("HWR").warning("Exiting Sample Changer 1s timer task") def _on_timer_update_exit(self, task): - logging.warning("Exiting Sample Changer update timer task") + logging.getLogger("HWR").warning("Exiting Sample Changer update timer task") @task def __timer_1s_task(self, *args): @@ -729,7 +729,7 @@ def _do_reset(self): def _execute_task(self, task, wait, method, *args): self.assert_can_execute_task() - logging.debug("Start " + SampleChangerState.tostring(task)) + logging.getLogger("HWR").debug("Start " + SampleChangerState.tostring(task)) self.task = task self.task_error = None self._set_state(task) @@ -779,9 +779,9 @@ def _on_task_failed(self, task, exception): def _on_task_ended(self, task): try: e = task.get() - logging.debug("Task ended. Return value: " + str(e)) + logging.getLogger("HWR").debug("Task ended. Return value: " + str(e)) except Exception as errmsg: - logging.error("Error while executing sample changer task: %s", str(errmsg)) + logging.getLogger("HWR").error("Error while executing sample changer task: %s", str(errmsg)) def _set_state(self, state=None, status=None): if (state is not None) and (self.state != state): diff --git a/mxcubecore/HardwareObjects/queue_entry.py b/mxcubecore/HardwareObjects/queue_entry.py index 77132678be..8874b72cdc 100644 --- a/mxcubecore/HardwareObjects/queue_entry.py +++ b/mxcubecore/HardwareObjects/queue_entry.py @@ -742,11 +742,11 @@ def collect_dc(self, dc, list_item): if ( dc.run_online_processing - and acq_1.acquisition_parameters.num_images > 4 and HWR.beamline.online_processing is not None ): + HWR.beamline.online_processing.data_collection = dc self.online_processing_task = gevent.spawn( - HWR.beamline.online_processing.run_processing, dc + HWR.beamline.online_processing.prepare_processing ) empty_cpos = queue_model_objects.CentredPosition() @@ -1009,44 +1009,51 @@ def start_char(self): self.edna_result = HWR.beamline.characterisation.characterise(edna_input) if self.edna_result: - log.info("Characterisation completed.") + if self.edna_result != 'NOT DONE': + log.info("Characterisation completed.") - char.html_report = HWR.beamline.characterisation.get_html_report( - self.edna_result - ) - - try: - strategy_result = ( - self.edna_result.getCharacterisationResult().getStrategyResult() + char.html_report = HWR.beamline.characterisation.get_html_report( + self.edna_result ) - except Exception: - strategy_result = None - if strategy_result: - collection_plan = strategy_result.getCollectionPlan() - else: - collection_plan = None + try: + strategy_result = ( + self.edna_result.getCharacterisationResult().getStrategyResult() + ) + except Exception: + strategy_result = None - if collection_plan: - if char.auto_add_diff_plan: - # default action - self.handle_diffraction_plan(self.edna_result, None) + if strategy_result: + collection_plan = strategy_result.getCollectionPlan() else: - collections = HWR.beamline.characterisation.dc_from_output( - self.edna_result, char.reference_image_collection - ) - char.diffraction_plan.append(collections) - HWR.beamline.queue_model.emit( - "diff_plan_available", (char, collections) - ) + collection_plan = None + + if collection_plan: + if char.auto_add_diff_plan: + # default action + self.handle_diffraction_plan(self.edna_result, None) + else: + collections = HWR.beamline.characterisation.dc_from_output( + self.edna_result, char.reference_image_collection + ) + char.diffraction_plan.append(collections) + HWR.beamline.queue_model.emit( + "diff_plan_available", (char, collections) + ) - self.get_view().setText(1, "Done") + self.get_view().setText(1, "Done") + else: + self.get_view().setText(1, "No result") + self.status = QUEUE_ENTRY_STATUS.WARNING + log.warning( + "Characterisation completed " + + "successfully but without collection plan." + ) else: - self.get_view().setText(1, "No result") + self.get_view().setText(1, "Not run") self.status = QUEUE_ENTRY_STATUS.WARNING log.warning( - "Characterisation completed " - + "successfully but without collection plan." + "Characterisation not initiated." ) else: self.get_view().setText(1, "Charact. Failed") diff --git a/mxcubecore/HardwareObjects/queue_model_objects.py b/mxcubecore/HardwareObjects/queue_model_objects.py index 4e5e3109e0..5c78ae59aa 100644 --- a/mxcubecore/HardwareObjects/queue_model_objects.py +++ b/mxcubecore/HardwareObjects/queue_model_objects.py @@ -32,6 +32,11 @@ from mxcubecore import HardwareRepository as HWR +try: + from collections import OrderedDict +except ImportError: + from ordereddict import OrderedDict + __copyright__ = """ Copyright © 2010 - 2020 by MXCuBE Collaboration """ __license__ = "LGPLv3+" @@ -1857,394 +1862,182 @@ def get_path_template(self): return self.path_template + class GphlWorkflow(TaskNode): - def __init__(self): + def __init__(self, workflow_hwobj): TaskNode.__init__(self) - - workflow_hwobj = HWR.beamline.gphl_workflow - - # Workflow start attriutes + self.workflow_hwobj = workflow_hwobj self.path_template = PathTemplate() + self._name = str() self._type = str() - self.shape = str() - # string. Only active mode currently is 'MASSIF1' - self.automation_mode = None - # Automation mode charancterisation parameters. Replace UI queried values - self.auto_char_params = {} - # Automation mode acquisition parameters. Replace UI queried values - self.auto_acq_params = {} - # Full path of characterisation data directory, if pre-acquired - # self.characterisation_directory = None - - # Pre-strategy attributes - self.space_group = str() - self.crystal_system = str() - self.point_group = None - self.bravais_lattice = None - self._cell_parameters = () - self.beamstop_setting = None - self.wavelengths = () - self.detector_setting = None - self.aimed_resolution = None - self.goniostat_translations = () - self.strategy = str() - self.characterisation_strategy = str() - self.strategy_options = {} - - # Pre-collection attributes - # Attributes for workflow - self.exposure_time = 0.0 - self.image_width = 0.0 - self.wedge_width = 0.0 - self.transmission = 0.0 - self.snapshot_count = 2 - # Workflow interleave order (string). - # Slowest changing first, characters 'g' (Goniostat position); - # 's' (Scan number), 'b' (Beam wavelength), 'd' (Detector position) - self.interleave_order = "gs" - - # Centring handling and MXCuBE-side flow - self.recentring_mode = "sweep" - self.current_rotation_id = None - self.characterisation_done = False - # Dose budget handling - self.maximum_dose_budget = 20.0 - self.dose_budget = None - self.decay_limit = 25 - self.characterisation_budget_fraction = 0.05 - self.relative_rad_sensitivity = 1.0 - self.dose_consumed = 0.0 - self.strategy_length = 0.0 + self._characterisation_strategy = str() + self._interleave_order = str() + self._number = 0 + self._beam_energies = OrderedDict() + self._detector_resolution = None + self._space_group = None + self._crystal_system = None + self._point_group = None + self._cell_parameters = None + self._snapshot_count = None + self._centre_before_sweep = None + self._centre_before_scan = None + + self._dose_budget = None + self._characterisation_budget_fraction = 1.0 + self._relative_rad_sensitivity = 1.0 + + # HACK - to differentiate between characterisation and acquisition + # TODO remove when workflow gives relevant information + self.lattice_selected = False self.set_requires_centring(False) - self.set_from_dict(workflow_hwobj.settings["defaults"]) + # Workflow name (string) - == path_template.base_prefix. + def get_name(self): + return self._name - def set_from_dict(self, params_dict): - for dict_item in params_dict.items(): - if hasattr(self, dict_item[0]): - setattr(self, dict_item[0], dict_item[1]) + def set_name(self, value): + self._name = value - def set_pre_strategy_params( - self, - point_group="", - bravais_lattice="", - crystal_system="", - space_group=None, - cell_parameters=(), - resolution=None, - energies=(), - relative_rad_sensitivity=None, - strategy_options=None, - **unused): - """""" - - from mxcubecore.HardwareObjects.Gphl import GphlMessages - - # Order of precedence: space_group, point_group, bravais_lattice. - if space_group: - # Space group overrides point group and and bravais latice - self.space_group = space_group - self.point_group = None - self.bravais_lattice = None - else: - if point_group: - # To avoid compatibility problems, reset other parameters - # NB Crystal system follows from point group - self.space_group = None - self.point_group = point_group - self.bravais_lattice = None - if bravais_lattice: - # NB there are compatibility problems here - TODO - self.bravais_lattice = bravais_lattice - if cell_parameters: - self.cell_parameters = cell_parameters - - workflow_parameters = self.get_workflow_parameters() - - # NB this is an internal dictionary. DO NOT MODIFY - settings = HWR.beamline.gphl_workflow.settings - energy_tags = workflow_parameters.get( - "beam_energy_tags", (settings["default_beam_energy_tag"],) - ) - interleave_order = workflow_parameters.get("interleave_order") - if interleave_order: - self.interleave_order = interleave_order - - if energies: - if len(energy_tags) != len(energies): - raise ValueError( - "Strategy should have %s energies, value was %s" - % (len(energy_tags), energies) - ) - wavelengths = [] - for iii, role in enumerate(energy_tags): - wavelengths.append( - GphlMessages.PhasingWavelength( - wavelength= HWR.beamline.energy.get_wavelength(energies[iii]), - role=role - ) - ) - self.wavelengths = tuple(wavelengths) - else: - if len(energy_tags) != 1: - raise ValueError( - "Strategy should have %s explicit energies, values missing" - % len(energy_tags) - ) + # Workflow type (string). + def get_type(self): + return self._type - wavelength = self.wavelengths[0].wavelength + def set_type(self, value): + self._type = value - if self.detector_setting is None: - resolution = resolution or self.aimed_resolution - if resolution: - distance = HWR.beamline.resolution.resolution_to_distance( - resolution, wavelength - ) - orgxy = HWR.beamline.detector.get_beam_position( - distance, wavelength - ) - self.detector_setting = GphlMessages.BcsDetectorSetting( - resolution, orgxy=orgxy, Distance=distance - ) + # Workflow interleave order (string). + # Slowest changing first, characters 'g' (Goniostat position); + # 's' (Scan number), 'b' (Beam wavelength), 'd' (Detector position) + def get_interleave_order(self): + return self._interleave_order - self.strategy_options = { - "strategy_type": workflow_parameters["strategy_type"], - "angular_tolerance": settings["angular_tolerance"], - "maximum_chi": settings["maximum_chi"], - "variant": workflow_parameters["variants"][0], - } - if strategy_options: - self.strategy_options.update(strategy_options) - - def set_pre_acquisition_params( - self, - exposure_time=None, - image_width=None, - wedge_width=None, - transmission=None, - snapshot_count=None, - **unused - ): - """""" - if exposure_time: - self.exposure_time = float(exposure_time) - if image_width: - self.image_width = float(image_width) - if wedge_width: - self.wedge_width = float(wedge_width) - if transmission: - # NBNB TODO transmission must be calculated - # for chareacterisation and acquisition - self.transmission = float(transmission) - if snapshot_count: - self.snapshot_count = int(snapshot_count) - - def init_from_task_data(self, sample_model, params): - """ - sample_model is required as this may be called before the object is enqueued - params is a dictionary with structure determined by mxcube3 usage - - in this function it is used only for PathTemplate data and strategy_name - """ + def set_interleave_order(self, value): + self._interleave_order = value - from mxcubecore.HardwareObjects.Gphl import GphlMessages + # Starting run number. Unnecessary. + # Left in as it is modified by signal when edited. + def get_number(self): + logging.getLogger().warning( + "Attempt to get unused attribute GphlWorkflow.number" + ) + return None - # NB settings is an internal attribute DO NOT MODIFY - settings = HWR.beamline.gphl_workflow.settings - self.auto_char_params = copy.deepcopy(settings.get("auto_char_params", {})) - self.auto_char_params.update(params.pop("auto_char_params", {})) - self.auto_acq_params = copy.deepcopy(settings.get("auto_acq_params", {})) - self.auto_acq_params.update(params.pop("auto_acq_params", {})) + def set_number(self, value): + logging.getLogger().warning( + "Attempt to set unused attribute GphlWorkflow.number" + ) - automation_mode = params.get("automation_mode") - if automation_mode: - # Set automation defaults and parameters - self.automation_mode = automation_mode + # Detector resolution (determines detector distance). + def get_detector_resolution(self): + return self._detector_resolution - # Set path template - self.path_template.set_from_dict(params) + def set_detector_resolution(self, value): + self._detector_resolution = value - if params["prefix"]: - self.path_template.base_prefix = params["prefix"] - else: - self.path_template.base_prefix = HWR.beamline.session.get_default_prefix( - sample_model - ) + # role:value beam_energy dictionary (in keV) + def get_beam_energies(self): + return self._beam_energies.copy() - self.path_template.num_files = 0 - self.path_template.precision = "0" + str( - HWR.beamline.session["file_info"].get_property("precision", 4) - ) + def set_beam_energies(self, value): + self._beam_energies = OrderedDict(value) - self.path_template.directory = os.path.join( - HWR.beamline.session.get_base_image_directory(), params.get("subdir", "") - ) + # Space Group. + def get_space_group(self): + return self._space_group - self.path_template.process_directory = os.path.join( - HWR.beamline.session.get_base_process_directory(), params.get("subdir", ""), - ) + def set_space_group(self, value): + self._space_group = value - # Set crystal parameters from sample node - crystal = sample_model.crystals[0] - tpl = ( - crystal.cell_a, crystal.cell_b, crystal.cell_c, - crystal.cell_alpha, crystal.cell_beta, crystal.cell_gamma - ) - if all(tpl): - self.cell_parameters = tpl - self.space_group = crystal.space_group - self.protein_acronym = crystal.protein_acronym - - # Set to current wavelength for now - nothing else available - wavelength = HWR.beamline.energy.get_wavelength() - role = HWR.beamline.gphl_workflow.settings["default_beam_energy_tag"] - self.wavelengths = ( - GphlMessages.PhasingWavelength(wavelength=wavelength, role=role), - ) + # Characterisation strategy. + def get_characterisation_strategy(self): + return self._characterisation_strategy - # First set some parameters from defaults - default_parameters = HWR.beamline.get_default_acquisition_parameters() - self.aimed_resolution = default_parameters.resolution - self.exposure_time = default_parameters.exp_time - self.image_width = default_parameters.osc_range - - # Set parameters from diffraction plan - diffraction_plan = sample_model.diffraction_plan - if diffraction_plan: - # It is not clear if diffraction_plan is a dict or an object, - # and if so which kind - if hasattr(diffraction_plan, "radiationSensitivity"): - radiation_sensitivity = diffraction_plan.radiationSensitivity - else: - radiation_sensitivity = diffraction_plan.get("radiationSensitivity") + def set_characterisation_strategy(self, value): + self._characterisation_strategy = value - if radiation_sensitivity: - self.relative_rad_sensitivity = radiation_sensitivity + # Crystal system. + def get_crystal_system(self): + return self._crystal_system - if hasattr(diffraction_plan, "aimedResolution"): - resolution = diffraction_plan.aimedResolution - else: - resolution = diffraction_plan.get("aimedResolution") + def set_crystal_system(self, value): + self._crystal_system = value - if resolution: - self.aimed_resolution = resolution + # Point Group. + def get_point_group(self): + return self._point_group - # Swt paramaters from params dict - self.set_name(self.path_template.base_prefix) - self.set_type(params["strategy_name"]) - self.shape = params.get("shape", "") + def set_point_group(self, value): + self._point_group = value - def get_workflow_parameters(self): - """Get parameters dictionary for workflow strategy""" - for wfdict in HWR.beamline.gphl_workflow.get_available_workflows().values(): - for stratdict in wfdict["strategies"]: - if stratdict["title"] == self.get_type(): - return stratdict - raise ValueError("No GPhL workflow strategy named %s found" % self.get_type()) - - # Parameters for start of workflow - def get_path_template(self): - return self.path_template + # Dose budget (MGy, float). + def get_dose_budget(self): + return self._dose_budget - # Strategy type (string); e.g. 'phasing' - def get_type(self): - return self._type + def set_dose_budget(self, value): + self._dose_budget = value - def set_type(self, value): - self._type = value + # Fraction of dose budget intended for characterisation. + def get_characterisation_budget_fraction(self): + return self._characterisation_budget_fraction - # Run name equal to base_prefix - def get_name(self): - return self._name + def set_characterisation_budget_fraction(self, value): + self._characterisation_budget_fraction = value - def set_name(self, value): - self._name = value + # Radiation sensitivity of crystal, relative to a 'standard crystal'. + def get_relative_rad_sensitivity(self): + return self._relative_rad_sensitivity + + def set_relative_rad_sensitivity(self, value): + self._relative_rad_sensitivity = value # Cell parameters - sequence of six floats (a,b,c,alpha,beta,gamma) - @property - def cell_parameters(self): + def get_cell_parameters(self): return self._cell_parameters - @cell_parameters.setter - def cell_parameters(self, value): - self._cell_parameters = None + def set_cell_parameters(self, value): if value: if len(value) == 6: self._cell_parameters = tuple(float(x) for x in value) else: - raise ValueError("invalid value for cell_parameters: %s" % str(value)) - - def calculate_transmission(self): - """Calculate transmission matching current parameters""" - - transmission = None - strategy_length = self.strategy_length - energy = HWR.beamline.energy.calculate_energy(self.wavelengths[0].wavelength) - exposure_time = self.exposure_time - image_width = self.image_width - - flux_density = HWR.beamline.flux.get_average_flux_density(transmission=100.0) - if flux_density: - std_dose_rate = ( - HWR.beamline.flux.get_dose_rate_per_photon_per_mmsq(energy) - * flux_density - * 1.0e-6 # convert to MGy/s - ) + raise ValueError("cell_parameters %s does not have length six" % value) + else: + self._cell_parameters = None - if image_width and exposure_time and std_dose_rate: - experiment_time = exposure_time * strategy_length / image_width - max_dose = std_dose_rate * experiment_time - transmission = 100. * self.dose_budget / max_dose - if not transmission: - msg = ( - "Transmission could not be calculated from:\n" - " energy:%s keV, strategy_length:%s deg, exposure_time:%s s, image_width:%s deg, " - "flux_density:%s photons/mm^2" - ) - raise ValueError( - msg % (energy, strategy_length, exposure_time, image_width, flux_density) - ) - # - return transmission + # Number of snapshots to take at start of data collection. + def get_snapshot_count(self): + return self._snapshot_count - def apply_transmission(self): - """Reset dose_budget to match current transmission""" - transmission = self.calculate_transmission() - self.dose_budget = self.dose_budget * self.transmission / transmission + def set_snapshot_count(self, value): + self._snapshot_count = value - def apply_dose_budget(self): - """ - Set dose budget, changing transmission, and (if necessary) also exposure time - """ - transmission = self.calculate_transmission() - if transmission > 100.: - exposure_limits = HWR.beamline.detector.get_exposure_time_limits() - self.exposure_time = min( - exposure_limits[1], self.exposure_time * transmission / 100. - ) - self.transmission = 100 - self.apply_transmission() - else: - self.transmission = transmission + # (Re)centre before each sweep?. + def get_centre_before_sweep(self): + return self._centre_before_sweep - def reset_transmission(self): - """reset transmission to match current parameters, lowering dose budget if transmission goes over 100, - reducing dose if transmission goes over 100 + def set_centre_before_sweep(self, value): + self._centre_before_sweep = bool(value) - NB intended for running in auto mode, or for changing xposure)time etc.""" - transmission = self.calculate_transmission() - if transmission > 100.: - self.transmission = 100. - self.dose_budget = self.dose_budget * 100. / transmission - else: - self.transmission = transmission + # (Re)centre before each scan?. + def get_centre_before_scan(self): + return self._centre_before_scan - def get_default_dose_budget(self): - """Get resolution-dependent dose budget using configured values""" - resolution = self.detector_setting.resolution - result = 2 * resolution * resolution * math.log(100.0 / self.decay_limit) - # - return min(result, self.maximum_dose_budget) / self.relative_rad_sensitivity + def set_centre_before_scan(self, value): + self._centre_before_scan = bool(value) + + def get_path_template(self): + return self.path_template + + def get_workflow_parameters(self): + result = HWR.beamline.gphl_workflow.get_available_workflows().get( + self.get_type() + ) + if result is None: + raise RuntimeError( + "No parameters for unknown workflow %s" % repr(self.get_type()) + ) + return result class XrayImaging(TaskNode): def __init__(self, xray_imaging_params, acquisition=None, crystal=None, name=""): diff --git a/mxcubecore/HardwareRepository.py b/mxcubecore/HardwareRepository.py index 25bc4b087d..9f67192d6e 100644 --- a/mxcubecore/HardwareRepository.py +++ b/mxcubecore/HardwareRepository.py @@ -36,7 +36,9 @@ import importlib from datetime import datetime +#RB: no module named ruamel.yaml, conda environment update needed? from ruamel.yaml import YAML +#import yaml from mxcubecore.utils.conversion import string_types, make_table from mxcubecore.dispatcher import dispatcher @@ -53,9 +55,11 @@ # If you want to write out copies of the file, use typ="rt" instead # pure=True uses yaml version 1.2, with fewere gotchas for strange type conversions +#RB: since YAML doesnt exist, remove this line yaml = YAML(typ="safe", pure=True) # The following are not needed for load, but define the default style. yaml.default_flow_style = False +#RB: yaml module has no attribute indent, probably needs the ruamel version yaml.indent(mapping=4, sequence=4, offset=2) @@ -176,7 +180,9 @@ def load_from_yaml(configuration_file, role, _container=None, _table=None): (role, class_name, configuration_file, "%.1d" % load_time, msg1) ) msg0 = "Done loading contents" + #RB: critical bug, objects does not have an attibute items for role1, config_file in _objects.items(): + #for role1, config_file in _objects: fname, fext = os.path.splitext(config_file) if fext == ".yml": load_from_yaml( diff --git a/mxcubecore/Poller.py b/mxcubecore/Poller.py index a8c7401a03..4ccedd15ac 100644 --- a/mxcubecore/Poller.py +++ b/mxcubecore/Poller.py @@ -90,14 +90,11 @@ def __init__( self.error_callback_ref = saferef.safe_ref(error_callback) self.compare = compare self.old_res = NotInitializedValue - self.queue = queue.Queue() + self.queue = queue.Queue()#_threading.Queue() self.delay = 0 self.stop_event = Event() - if gevent_version < [1, 3, 0]: - self.async_watcher = getattr(gevent.get_hub().loop, "async")() - else: - self.async_watcher = gevent.get_hub().loop.async_() + self.async_watcher = gevent.get_hub().loop.async() def start_delayed(self, delay): self.delay = delay @@ -209,6 +206,7 @@ def run(self): if new_value: self.old_res = res self.queue.put(res) + self.async_watcher.send() sleep(self.polling_period / 1000.0) if error_cb is not None: diff --git a/mxcubecore/__init__.py b/mxcubecore/__init__.py index a15f6b3485..257be06aa4 100644 --- a/mxcubecore/__init__.py +++ b/mxcubecore/__init__.py @@ -80,7 +80,7 @@ def setLogFile(filename): # # log to rotating files # - hdlr = RotatingFileHandler(filename, "a", 1048576, 5) # 1 MB by file, 5 files max. + hdlr = RotatingFileHandler(filename, "a", 1048576, 15) # 1 MB by file, 5 files max. hdlr.setFormatter(_hwr_formatter) setLoggingHandler(hdlr) diff --git a/mxcubecore/configuration/alba_xaloc13/Qt4_graphics-manager.xml b/mxcubecore/configuration/alba_xaloc13/Qt4_graphics-manager.xml.unused similarity index 60% rename from mxcubecore/configuration/alba_xaloc13/Qt4_graphics-manager.xml rename to mxcubecore/configuration/alba_xaloc13/Qt4_graphics-manager.xml.unused index 4676f5b052..53bc4ae5f6 100755 --- a/mxcubecore/configuration/alba_xaloc13/Qt4_graphics-manager.xml +++ b/mxcubecore/configuration/alba_xaloc13/Qt4_graphics-manager.xml.unused @@ -1,6 +1,7 @@ - + - + + (1, 1.5, 2.) diff --git a/mxcubecore/configuration/alba_xaloc13/Qt4_testvideo.xml b/mxcubecore/configuration/alba_xaloc13/Qt4_testvideo.xml.unused similarity index 100% rename from mxcubecore/configuration/alba_xaloc13/Qt4_testvideo.xml rename to mxcubecore/configuration/alba_xaloc13/Qt4_testvideo.xml.unused diff --git a/mxcubecore/configuration/alba_xaloc13/backlight.xml b/mxcubecore/configuration/alba_xaloc13/backlight.xml index fcd5594dd9..9bd0ca754c 100755 --- a/mxcubecore/configuration/alba_xaloc13/backlight.xml +++ b/mxcubecore/configuration/alba_xaloc13/backlight.xml @@ -1,8 +1,8 @@ - + Back BackLightIn Brightness 0 - 9 - 0,30 + 35 + 0,35 diff --git a/mxcubecore/configuration/alba_xaloc13/beam-info.xml b/mxcubecore/configuration/alba_xaloc13/beam-info.xml deleted file mode 100755 index 4212e4d17e..0000000000 --- a/mxcubecore/configuration/alba_xaloc13/beam-info.xml +++ /dev/null @@ -1,11 +0,0 @@ - - bl13/ct/variables - - ImageCenterX - ImageCenterY - BeamWidth - BeamHeight - - 230.0 - 150.0 - diff --git a/mxcubecore/configuration/alba_xaloc13/beam.xml b/mxcubecore/configuration/alba_xaloc13/beam.xml new file mode 100755 index 0000000000..846245bbe4 --- /dev/null +++ b/mxcubecore/configuration/alba_xaloc13/beam.xml @@ -0,0 +1,12 @@ + + bl13/ct/variables + + ImageCenterX + ImageCenterY + BeamWidth + BeamHeight + + 230.0 + 150.0 + + diff --git a/mxcubecore/configuration/alba_xaloc13/beamline-setup.xml b/mxcubecore/configuration/alba_xaloc13/beamline-setup.xml deleted file mode 100755 index 4ea03efd3c..0000000000 --- a/mxcubecore/configuration/alba_xaloc13/beamline-setup.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ["MeshScan", "XrayCentering"] - - - True - - - True - - - - DECTRIS - pilatus - 6M_F - 0.172 - 0.172 - yes - True - - - - - 0.3 - 0.0 - 0.1 - 1 - 1 - 1 - 0 - 1 - 1 - - - - 0.040 - 0.0 - 0.1 - 1 - 1 - 1 - 0 - 100 - 1 - - - - -2165,2165 - 0.003,6000 - 1,9999 - - - - - 0.3 - 0.0 - 1 - 1 - 1 - 1 - 0 - 1 - 1 - - - - 0.040 - 0.0 - 0.5 - 1 - 1 - 1 - 0 - 100 - 1 - - diff --git a/mxcubecore/configuration/alba_xaloc13/beamline_config.yml b/mxcubecore/configuration/alba_xaloc13/beamline_config.yml old mode 100644 new mode 100755 index 6aa1af4bd5..cb7de5bdf8 --- a/mxcubecore/configuration/alba_xaloc13/beamline_config.yml +++ b/mxcubecore/configuration/alba_xaloc13/beamline_config.yml @@ -1,5 +1,3 @@ -# FIRST DRAFT of ALAB xaloc13 configuration. TO BE EDITED - # The class to initialise, and init parameters _initialise_class: class: mxcubecore.HardwareObjects.Beamline.Beamline @@ -27,89 +25,107 @@ _objects: # Hardware: - session: session.xml - machine_info: mach-info.xml - - transmission: transmission.xml - energy: energy.xml - - beam: beam-info.xml + - transmission: transmission.xml + #- beam_info: beam-info.xml + - beam: beam.xml - flux: flux.xml + - digital_zoom: digital-zoom.xml + - sample_view: sample-view.xml - detector: pilatus.xml - resolution: resolution.xml # - hutch_interlock: door-interlock-mockup.xml -# - safety_shutter: safshut.xml +# - safety_shutter: safety_shutter.xml - fast_shutter: fastshut.xml - sample_changer: cats.xml + - sample_changer_maintenance: catsmaint.xml # NBNB TODO remove plate_manipulater and treat as another smaple changer # - plate_manipulator: plate-manipulator.xml + - ln2shower: ln2shower.xml - diffractometer: mini-diff.xml - - graphics: Qt4_graphics-manager.xml + - supervisor: supervisor.xml - lims: dbconnection.xml - queue_manager: queue.xml - queue_model: queue-model.xml # Procedures: - collect: mxcollect.xml - - xrf_spectrum: xrf-spectrum-mockup.xml - - energy_scan: energyscan-mockup.xml + #- xrf_spectrum: xrf-spectrum-mockup.xml + #- energy_scan: energyscan.xml # - imaging: xray-imaging.xml # Only in EMBL as of 201907 - gphl_workflow: gphl-workflow.xml - gphl_connection: gphl-setup.xml - # - centring: centring.xml + - centring: centring-math.xml # Analysis: - - offline_processing: auto-processing.xml - - online_processing: parallel-processing.xml - - characterisation: data-analysis.xml + - image_tracking: image-tracking.xml + - offline_processing: offline-processing.xml + - online_processing: online-processing.xml + - characterisation: characterisation.xml + - xml_rpc_server: xml-rpc-server.xml + - cryostream: cryostream.xml # - beam_realign: # Skipped - optional # Non-object attributes: advanced_methods: - MeshScan - XrayCentering tunable_wavelength: true -disable_num_passes: false +disable_num_passes: true run_number: 1 default_acquisition_parameters: default: # Default values, also used for standard acquisition. # Values not given in other dictionaries are taken from here - exp_time: 0.3 # (s) exposure time + exp_time: 0.01 # (s) exposure time osc_start: 0.0 # (degrees) Only used if no current angle found osc_range: 0.1 # (degrees) num_passes: 1 # (int) first_image: 1 # (int) overlap: 0 - num_images: 1 # (int) - detector_binning_mode: 1 # (int) + num_images: 100 # (int) + # detector_binning_mode: 1 # Removed as not in practice used. inverse_beam: false # (bool) take_dark_current: true # (bool) skip_existing_images: true # (bool) take_snapshots: true # (bool) + kappa_phi: 0 helical: # Defaults for helical scan. Missing values are taken from default - exp_time: 0.04 # (s) exposure time - num_images: 100 + exp_time: 0.01 # (s) exposure time characterisation: # Defaults for chareacterisation. Missing values are taken from default - osc_range: 1.0 + exp_time: 0.05 # (s) exposure time + osc_range: 0.1 - advanced: + mesh: # Defaults for 'advanced' acquisition. Missing values are taken from default - exp_time: 0.04 # (s) exposure time - osc_range: 0.5 + exp_time: 0.02 # (s) exposure time + osc_range: 0.0 num_images: 100 + cell_counting: inverse-zig-zag + cell_spacing: vertical,horizontal + mesh_center: top-left + + # The next lines cause an error in the beamline code + #advanced: + # Defaults for 'advanced' acquisition. Missing values are taken from default + # exp_time: 0.04 # (s) exposure time + # osc_range: 0.01 acquisition_limit_values: exposure_time: # (s) - - 0.003 - - 6000.0 + - 0.01 + - 1000.0 osc_range: # (degrees) - - -2165.0 - - 2165.0 + - -2160.0 + - 2160.0 number_of_images: # (int) - 1 - 9999 -# kappa: # (degrees) -# - 0.0 -# - 180.0 -# kappa_phi: # (degrees) -# - 0.0 -# - 360.0 + kappa: # (degrees) + - -1.0 + - 180.0 + kappa_phi: # (degrees) + - -720.0 + - 720.0 diff --git a/mxcubecore/configuration/alba_xaloc13/blight.xml b/mxcubecore/configuration/alba_xaloc13/blight.xml deleted file mode 100755 index 01abdd18af..0000000000 --- a/mxcubecore/configuration/alba_xaloc13/blight.xml +++ /dev/null @@ -1,11 +0,0 @@ - - BLightZoom - ioregister/eh_zoom_tangoior_ctrl/2 - blight - blight - Value - State - Labels - 200 - 0.001 - diff --git a/mxcubecore/configuration/alba_xaloc13/bstopz.xml b/mxcubecore/configuration/alba_xaloc13/bstopz.xml index 5ef508770b..07600b5ada 100755 --- a/mxcubecore/configuration/alba_xaloc13/bstopz.xml +++ b/mxcubecore/configuration/alba_xaloc13/bstopz.xml @@ -1,4 +1,4 @@ - + Beam Stop Z bstopz bstopz diff --git a/mxcubecore/configuration/alba_xaloc13/calibration.xml b/mxcubecore/configuration/alba_xaloc13/calibration.xml.unused similarity index 89% rename from mxcubecore/configuration/alba_xaloc13/calibration.xml rename to mxcubecore/configuration/alba_xaloc13/calibration.xml.unused index d64e4c5da0..d753cdafb2 100755 --- a/mxcubecore/configuration/alba_xaloc13/calibration.xml +++ b/mxcubecore/configuration/alba_xaloc13/calibration.xml.unused @@ -1,4 +1,4 @@ - + Calibration bl13/ct/variables OAV_PIXELSIZE_X diff --git a/mxcubecore/configuration/alba_xaloc13/cats.xml b/mxcubecore/configuration/alba_xaloc13/cats.xml index ab2d495d07..5101a4e7f2 100755 --- a/mxcubecore/configuration/alba_xaloc13/cats.xml +++ b/mxcubecore/configuration/alba_xaloc13/cats.xml @@ -1,38 +1,89 @@ - + - Cats - bl13/eh/cats + CATS + bl13/eh/cats 3 - - False 5 True - MountingPosition - GoTransferPhase - GoSampleViewPhase - CurrentPhase - Abort - State - DetDistance + State + Status + Powered + PathRunning + Path + RecoveryNeeded + PathSafe + NumSampleOnDiff + LidSampleOnDiff + Barcode + di_PRI_SOM + di_AllLidsClosed + Tool + CassettePresence + di_Cassette1Presence + di_Cassette2Presence + di_Cassette3Presence + di_Cassette4Presence + di_Cassette5Presence + di_Cassette6Presence + di_Cassette7Presence + di_Cassette8Presence + di_Cassette9Presence + + di_CollisonSensorOK + do_PRO5_IDL + do_PRO6_RAH + do_PRO7_RI1 + do_PRO8_RI2 + CurrentNumberOfSoaking + LidSampleOnTool + NumSampleOnTool - di_PRI4_SOM - PathSafe + put + get + getput + abort + powerOn + powerOff + put_bcrd + getput_bcrd + barcode - put_HT - get_HT - getput_HT + put_HT + get_HT + getput_HT + getpuckpick + clear_memory + settool + settool + recoverFailure + pick - put_bcrd - getput_bcrd + MountingPosition + GoSampleViewPhase + GoSampleViewPhase + CurrentPhase + State + AperturePosition + DetDistanceSafe + Abort + DetDistance + position + position - barcode + GoSampleViewPhase + GoTransferPhase + GoSampleViewPhase + Abort + bl13/door/05 + cats_recover_collision + diff --git a/mxcubecore/configuration/alba_xaloc13/catsmaint.xml b/mxcubecore/configuration/alba_xaloc13/catsmaint.xml index f17574a8e9..0dbef35f48 100755 --- a/mxcubecore/configuration/alba_xaloc13/catsmaint.xml +++ b/mxcubecore/configuration/alba_xaloc13/catsmaint.xml @@ -1,23 +1,35 @@ - - CatsMaint + + CatsMaintenance bl13/eh/cats + - - - MountingPosition - - Abort - + + Abort - - - Barcode do_PRO6_RAH + + + SampleOnMagnet + MountingPosition diff --git a/mxcubecore/configuration/alba_xaloc13/centring-math.xml b/mxcubecore/configuration/alba_xaloc13/centring-math.xml new file mode 100755 index 0000000000..8b1d6ebc59 --- /dev/null +++ b/mxcubecore/configuration/alba_xaloc13/centring-math.xml @@ -0,0 +1,59 @@ + + + + + phiy + [1, 0, 0] + translation + /omegax + + + + + phiz + [0, 0, 1] + translation + /omegaz + + + + phi + [-1, 0, 0] + rotation + /omega + + + + + sampx + + [0, 1, 0] + translation + /centx + + + + sampy + + [0, 0, 1] + translation + /centy + + + + + X + [1, 0, 0] + + + Y + [0, 0, -1] + + + + 2 + 3 + 300 + diff --git a/mxcubecore/configuration/alba_xaloc13/centx.xml b/mxcubecore/configuration/alba_xaloc13/centx.xml index af00f00718..7f33513397 100755 --- a/mxcubecore/configuration/alba_xaloc13/centx.xml +++ b/mxcubecore/configuration/alba_xaloc13/centx.xml @@ -1,5 +1,6 @@ - + Center X centx CentX + 0.0002 diff --git a/mxcubecore/configuration/alba_xaloc13/centy.xml b/mxcubecore/configuration/alba_xaloc13/centy.xml index f7807bbe0b..ce7814dc2b 100755 --- a/mxcubecore/configuration/alba_xaloc13/centy.xml +++ b/mxcubecore/configuration/alba_xaloc13/centy.xml @@ -1,5 +1,6 @@ - + Center Y centy CentY + 0.0002 diff --git a/mxcubecore/configuration/alba_xaloc13/characterisation.xml b/mxcubecore/configuration/alba_xaloc13/characterisation.xml new file mode 100755 index 0000000000..ed23fa4581 --- /dev/null +++ b/mxcubecore/configuration/alba_xaloc13/characterisation.xml @@ -0,0 +1,27 @@ + + + + + + + + + /beamlines/bl13/controls/production/git/bl13_processing/edna-mx/XSDataInput_templates/mxcube/edna_defaults.xml + + False + opbl13 + + + + pcbl1309 + + + /usr/local/sdm/processing_xaloc + + + /beamlines/bl13/sdm/production/processing_xaloc/edna-mx/strategy/mxcube/edna-mx.strategy.first.ssh + /beamlines/bl13/sdm/production/processing_xaloc/edna-mx/strategy/mxcube/run_local_strategy.sh + + + diff --git a/mxcubecore/configuration/alba_xaloc13/cluster.xml b/mxcubecore/configuration/alba_xaloc13/cluster.xml new file mode 100755 index 0000000000..5f27f360e1 --- /dev/null +++ b/mxcubecore/configuration/alba_xaloc13/cluster.xml @@ -0,0 +1,12 @@ + + opbl13 + claxaloc01 + + /beamlines/bl13/sdm/production/processing_xaloc + + + {'plugin': 'EDPluginControlInterfaceToMXCuBEv1_3', 'script': 'edna-mx/strategy/mxcube/edna-mx.strategy.sl'} + {'plugin': 'EDPluginControlEDNAprocv1_0', 'script': 'edna-mx/ednaproc/mxcube/edna-mx.ednaproc.sl'} + {'plugin': 'EDPluginControlAutoPROCv1_1', 'script': 'edna-mx/autoproc/mxcube/edna-mx.autoproc.sl', 'configdef': 'edna-mx/autoproc/mxcube/config.def'} + {'plugin': 'EDPluginControlXia2DIALSv1_0', 'script': 'edna-mx/xia2dials/mxcube/edna-mx.xia2dials.sl'} + diff --git a/mxcubecore/configuration/alba_xaloc13/cryostream.xml b/mxcubecore/configuration/alba_xaloc13/cryostream.xml new file mode 100644 index 0000000000..a85c1123d1 --- /dev/null +++ b/mxcubecore/configuration/alba_xaloc13/cryostream.xml @@ -0,0 +1,8 @@ + + Cryostream + bl13/eh/oxfcryo + + GasTemp + State + + diff --git a/mxcubecore/configuration/alba_xaloc13/cstagex.xml b/mxcubecore/configuration/alba_xaloc13/cstagex.xml new file mode 100755 index 0000000000..896ab6e895 --- /dev/null +++ b/mxcubecore/configuration/alba_xaloc13/cstagex.xml @@ -0,0 +1,8 @@ + + StageX + cstagex + StageX + 45 + + 0.0001 + diff --git a/mxcubecore/configuration/alba_xaloc13/cstagey.xml b/mxcubecore/configuration/alba_xaloc13/cstagey.xml new file mode 100755 index 0000000000..fbe1af0b3d --- /dev/null +++ b/mxcubecore/configuration/alba_xaloc13/cstagey.xml @@ -0,0 +1,8 @@ + + StageY + cstagey + StageY + 45 + + 0.0001 + diff --git a/mxcubecore/configuration/alba_xaloc13/cstagez.xml b/mxcubecore/configuration/alba_xaloc13/cstagez.xml new file mode 100755 index 0000000000..d013eb6af0 --- /dev/null +++ b/mxcubecore/configuration/alba_xaloc13/cstagez.xml @@ -0,0 +1,8 @@ + + StageZ + cstagez + StageZ + 45 + + 0.0001 + diff --git a/mxcubecore/configuration/alba_xaloc13/dbconnection.xml b/mxcubecore/configuration/alba_xaloc13/dbconnection.xml index 13f3ce537f..b6a78010c5 100755 --- a/mxcubecore/configuration/alba_xaloc13/dbconnection.xml +++ b/mxcubecore/configuration/alba_xaloc13/dbconnection.xml @@ -1,13 +1,14 @@ - + proposal ldap - https://ispybtest.cells.es/ispyb/ispyb-ws/ispybWS/ + + https://ispyb.cells.es/ispyb/ispyb-ws/ispybWS/ - user - password + wservice + jS625Kyg*3DA,;:z ToolsForCollectionWebService @@ -24,7 +25,7 @@ mxCuBE 1.0 works with the new xml files (ie. cherry picking commits from master to 1.0 or merging) --> - MX-XALOC + MX-BL13 mx diff --git a/mxcubecore/configuration/alba_xaloc13/detector-distance.xml b/mxcubecore/configuration/alba_xaloc13/detector-distance.xml index 8778b6c0ca..17c2cc444f 100755 --- a/mxcubecore/configuration/alba_xaloc13/detector-distance.xml +++ b/mxcubecore/configuration/alba_xaloc13/detector-distance.xml @@ -1,4 +1,4 @@ - + Detector Distance detsamdis Detector Distance diff --git a/mxcubecore/configuration/alba_xaloc13/digital-zoom.xml b/mxcubecore/configuration/alba_xaloc13/digital-zoom.xml new file mode 100755 index 0000000000..8887abdf83 --- /dev/null +++ b/mxcubecore/configuration/alba_xaloc13/digital-zoom.xml @@ -0,0 +1,11 @@ + + Zoom + bl13/eh/bzoomspecific + zoom + + + zoom_index + State + + + diff --git a/mxcubecore/configuration/alba_xaloc13/edna_defaults.xml b/mxcubecore/configuration/alba_xaloc13/edna_defaults.xml index 5f2bd94ba4..cf70d74fe9 100755 --- a/mxcubecore/configuration/alba_xaloc13/edna_defaults.xml +++ b/mxcubecore/configuration/alba_xaloc13/edna_defaults.xml @@ -17,7 +17,7 @@ 1.283000e+11 - 0.1 + 0.05 diff --git a/mxcubecore/configuration/alba_xaloc13/energy.xml b/mxcubecore/configuration/alba_xaloc13/energy.xml index 2449104923..5cd8f4feb9 100755 --- a/mxcubecore/configuration/alba_xaloc13/energy.xml +++ b/mxcubecore/configuration/alba_xaloc13/energy.xml @@ -1,6 +1,7 @@ - + Energy + True diff --git a/mxcubecore/configuration/alba_xaloc13/energy_motor.xml b/mxcubecore/configuration/alba_xaloc13/energy_motor.xml index f40ab7e3ba..f2854759a7 100755 --- a/mxcubecore/configuration/alba_xaloc13/energy_motor.xml +++ b/mxcubecore/configuration/alba_xaloc13/energy_motor.xml @@ -1,8 +1,13 @@ - - Energy - ealign - energy + + Energy Motor + Ealign + + ealign + 0.0005 - 45 + + 0.0005 + 0.5 + diff --git a/mxcubecore/configuration/alba_xaloc13/fastshut.xml b/mxcubecore/configuration/alba_xaloc13/fastshut.xml index 4da1394c91..d48a3e4497 100755 --- a/mxcubecore/configuration/alba_xaloc13/fastshut.xml +++ b/mxcubecore/configuration/alba_xaloc13/fastshut.xml @@ -1,5 +1,8 @@ - + Fast Shutter + + 0.005 + IdleState Start Stop diff --git a/mxcubecore/configuration/alba_xaloc13/flux.xml b/mxcubecore/configuration/alba_xaloc13/flux.xml index 6895eb068c..1bd98f3174 100644 --- a/mxcubecore/configuration/alba_xaloc13/flux.xml +++ b/mxcubecore/configuration/alba_xaloc13/flux.xml @@ -1,2 +1,9 @@ - + + Flux + value + position + fluxlast + fluxlastnorm + + 1.5E12 diff --git a/mxcubecore/configuration/alba_xaloc13/frontend.xml b/mxcubecore/configuration/alba_xaloc13/frontend.xml index e4d5fa3434..ba85ec8bf1 100755 --- a/mxcubecore/configuration/alba_xaloc13/frontend.xml +++ b/mxcubecore/configuration/alba_xaloc13/frontend.xml @@ -1,4 +1,4 @@ - + Front End bl13/ct/eps-plc-01 fe_open diff --git a/mxcubecore/configuration/alba_xaloc13/frontlight.xml b/mxcubecore/configuration/alba_xaloc13/frontlight.xml index 7388cf0446..67ec725276 100755 --- a/mxcubecore/configuration/alba_xaloc13/frontlight.xml +++ b/mxcubecore/configuration/alba_xaloc13/frontlight.xml @@ -1,7 +1,7 @@ - + Front Brightness State - 0,30 + 0,100 2 diff --git a/mxcubecore/configuration/alba_xaloc13/gphl-setup.xml b/mxcubecore/configuration/alba_xaloc13/gphl-setup.xml index fe8b677332..407a2e20f6 100644 --- a/mxcubecore/configuration/alba_xaloc13/gphl-setup.xml +++ b/mxcubecore/configuration/alba_xaloc13/gphl-setup.xml @@ -3,67 +3,117 @@ - replaced-by-GphlWorkflow.file_paths['scripts'] + + + + /beamlines/bl13/controls/gphl/latest/mxcube_setup/ + /beamlines/bl13/controls/gphl/latest/gphl_release/latest + + + + + + + + + + + + + + + + + GPHL + + persistence + + + + + + + + + + + + + - /users/blissadm/bin/java + + /usr/bin/java + + + + + {GPHL_RELEASE}/autoPROC/bin/linux64 + + + - /users/blissadm/local/gphl/gphl_java_classes/* + {GPHL_SETUP}/wfjars/* + + + gphl_beamline_config + + + {GPHL_SETUP}test_samples + + + + - /users/blissadm/local/gphl/gphl_latest/exe/ - - /opt/pxsoft/bin/xds_par - - - - - + + + {GPHL_RELEASE} + + + + /beamlines/bl13/commissioning/software/xds/XDS-INTEL64_Linux_x86_64/xds_par + + + - + {GPHL_SETUP}/scripts/run_stratcal_wrap.py - - + + {GPHL_SETUP}/scripts/simcal - + - + - {LOCAL_SCRIPTS}/aP_wf_rotcal - - + + {GPHL_SETUP}/scripts/aP_wf_rotcal - - GPHL + + - - - - - - - - + diff --git a/mxcubecore/configuration/alba_xaloc13/gphl-workflow.xml b/mxcubecore/configuration/alba_xaloc13/gphl-workflow.xml new file mode 100644 index 0000000000..ba6bdc2438 --- /dev/null +++ b/mxcubecore/configuration/alba_xaloc13/gphl-workflow.xml @@ -0,0 +1,456 @@ + + + + + + + + + 0.1 0.05 0.2 + + + + + + + current + + + 15 + + + 5 + + + InitialCharacterisation_6_5 + InitialCharacterisation_12_3 + InitialCharacterisation_12_4 + InitialCharacterisation_12_5 + + + + + + + 5.0 + + + + 10.0 + True + + + + 20.0 + + + + + + + Thaumatin + + P41212 + 57.847 + 57.847 + 150.125 + 90 + 90 + 90 + + + germanate + Ia-3d + 51.2487 + 51.2487 + 51.2487 + 90 + 90 + 90 + + + CubicInsulin + + I213 + 77.9 + 77.9 + 77.9 + 90 + 90 + 90 + + + HEWLysozyme + + P43212 + 78.54 + 78.45 + 37.70 + 90 + 90 + 90 + + + Se-Met_FAE + + P212121 + 65.381 + 108.793 + 113.877 + 90 + 90 + 90 + + + + + + + + + + + + + persistence + + + + + + + + + + + + + gphl_wf_ + + + + + + + generic + + + + + gphl_data + + ib_interleaved + + interleaved + + + + + + + + + UTF-8 + + + + + + + wf + + + + + + + + + false + + + + + 26.0 + 1.5e-3 + 0.2 + + + + + + true + + + 48 + 1 + + + + + + + co.gphl.wf.workflows.WFSimpleCharToProcessing + phasing + + Single wavelength data acquisition, strategy for phasing + Includes initial characterisation and complete collection + + + + + + gs + + + + Acquisition + + 12.7 + + + + SAD_ + + + + + co.gphl.wf.workflows.WFSimpleCharToProcessing + phasing + + Two-wavelength MAD data acquisition. + Includes initial characterisation and complete collection + + + + + gsb + + + + Peak + + 12.7 + + + Remote + + 12.72 + + + + MAD2_ + + + + + co.gphl.wf.workflows.WFSimpleCharToProcessing + phasing + + Three-wavelength MAD data acquisition. + Includes initial characterisation and complete collection + + + + + gsb + + + + Peak + + 12.7 + + + Rising_Inflection + + 12.69 + + + Falling_Inflection + + 12.71 + + + + MAD3_ + + + + + co.gphl.wf.workflows.WFSimpleCharToProcessing + native_short + + Single wavelength data acquisition for native data collection + Includes initial characterisation and complete collection. + Fast, 1 sweep (2 for triclinic and monoclinic), chiMax = 20deg + + + + + + + + + + + Acquisition + + 12.7 + + + + Native1_ + + + + + co.gphl.wf.workflows.WFSimpleCharToProcessing + native_two360 + + Single wavelength data acquisition for native data collection + Includes initial characterisation and complete collection. + Medium, 2 sweeps (3 for triclinic and monoclinic), chiMax = 35deg + + + + + + + + + + + Acquisition + + 12.7 + + + + Native2_ + + + + + co.gphl.wf.workflows.WFSimpleCharToProcessing + native_antishadow + + Single wavelength data acquisition for native data collection + Includes initial characterisation and complete collection. + Strategy for optimal distribution of redundancy, + 3-4 sweeps. Uses full kappa range. + May default to medium strategy for sixfold and cubic symmetries. + + + + + + + + + + + Acquisition + + 12.7 + + + + Native3_ + + + + + co.gphl.wf.workflows.WFTransCal + transcal + Translational calibration. + Designed for use by beamline personnel. + Will produce a series of goniostat positions compatible with + the inbuilt collision checker, move the goniostat to each + position, and ask for centring. + + + + transcal + + + + + + transcal_2stage.json + + + + + + + + + + co.gphl.wf.workflows.WFDiffractCal + diffractcal + Diffractometer calibration. + Designed for use by beamline personnel. + + + + + + + gs + + Dcalib2_ + + DiffractCal_ex + + + + diffractcal + + multiorientation + + + + + + + + + + co.gphl.wf.workflows.WFDiffractCal + diffractcal + Diffractometer calibration. + Designed for use by beamline personnel. + + + + + + + gs + + Dcalib1_ + + DiffractCal + + + + diffractcal + + multiorientation + + + + + + + + + + + + + diff --git a/mxcubecore/configuration/alba_xaloc13/image-tracking.xml b/mxcubecore/configuration/alba_xaloc13/image-tracking.xml new file mode 100644 index 0000000000..7b98a8db6b --- /dev/null +++ b/mxcubecore/configuration/alba_xaloc13/image-tracking.xml @@ -0,0 +1,14 @@ + + bl13/ct/pilatus + + + + + + send_image + + + + + + diff --git a/mxcubecore/configuration/alba_xaloc13/instanceconnection.xml b/mxcubecore/configuration/alba_xaloc13/instanceconnection.xml index af09626ee8..04d78fff4c 100755 --- a/mxcubecore/configuration/alba_xaloc13/instanceconnection.xml +++ b/mxcubecore/configuration/alba_xaloc13/instanceconnection.xml @@ -1,4 +1,4 @@ - + 14001 diff --git a/mxcubecore/configuration/alba_xaloc13/kappa.xml b/mxcubecore/configuration/alba_xaloc13/kappa.xml index fd3ec4f943..136e81fb00 100755 --- a/mxcubecore/configuration/alba_xaloc13/kappa.xml +++ b/mxcubecore/configuration/alba_xaloc13/kappa.xml @@ -1,5 +1,6 @@ - + Kappa kappa Kappa + 0.0005 diff --git a/mxcubecore/configuration/alba_xaloc13/kappaalign.xml b/mxcubecore/configuration/alba_xaloc13/kappaalign.xml new file mode 100755 index 0000000000..bb1e6da2d4 --- /dev/null +++ b/mxcubecore/configuration/alba_xaloc13/kappaalign.xml @@ -0,0 +1,5 @@ + + Kappa + kappaalign + Kappa + diff --git a/mxcubecore/configuration/alba_xaloc13/kappaphi.xml b/mxcubecore/configuration/alba_xaloc13/kappaphi.xml index 17ce54da63..6aeb7f63b4 100755 --- a/mxcubecore/configuration/alba_xaloc13/kappaphi.xml +++ b/mxcubecore/configuration/alba_xaloc13/kappaphi.xml @@ -1,5 +1,6 @@ - + Kappa Phi - kappaphi + phi KappaPhi + 0.0005 diff --git a/mxcubecore/configuration/alba_xaloc13/kappaphialign.xml b/mxcubecore/configuration/alba_xaloc13/kappaphialign.xml new file mode 100755 index 0000000000..c86d9643ae --- /dev/null +++ b/mxcubecore/configuration/alba_xaloc13/kappaphialign.xml @@ -0,0 +1,5 @@ + + Kappa Phi + phialign + KappaPhi + diff --git a/mxcubecore/configuration/alba_xaloc13/limavideo.xml b/mxcubecore/configuration/alba_xaloc13/limavideo.xml index f82bb707ab..1570433037 100755 --- a/mxcubecore/configuration/alba_xaloc13/limavideo.xml +++ b/mxcubecore/configuration/alba_xaloc13/limavideo.xml @@ -1,20 +1,21 @@ - - - basler - yuv422p + + + bzoom + rgb24 -
84.89.227.72
- bl13/eh/basler_oav + bl13/eh/bzoom - 0.24 + 1 - 0.08 - (False, False) + + (True, False) 30 + + 900 670 diff --git a/mxcubecore/configuration/alba_xaloc13/ln2shower.xml b/mxcubecore/configuration/alba_xaloc13/ln2shower.xml new file mode 100755 index 0000000000..87474417db --- /dev/null +++ b/mxcubecore/configuration/alba_xaloc13/ln2shower.xml @@ -0,0 +1,20 @@ + + Ln2 Shower + bl13/eh/ln2pump + + + + operation + State + + False + + bl13/door/05 + ln2shower_wash + ln2shower_cold + ln2shower_setflow + ln2shower_on + ln2shower_off + ln2shower_sleep + + diff --git a/mxcubecore/configuration/alba_xaloc13/mach-info.xml b/mxcubecore/configuration/alba_xaloc13/mach-info.xml index 17e91ab5e2..2f7aa4257c 100755 --- a/mxcubecore/configuration/alba_xaloc13/mach-info.xml +++ b/mxcubecore/configuration/alba_xaloc13/mach-info.xml @@ -1,7 +1,7 @@ - - Mach - mach/ct/gateway - State - Current - TopUpRemaining + + MachineInfo + tango://alba03.cells.es:10000/sr/ct/gateway + state + current + topupremaining diff --git a/mxcubecore/configuration/alba_xaloc13/mini-diff.xml b/mxcubecore/configuration/alba_xaloc13/mini-diff.xml index 51af0ce18f..383817af7f 100755 --- a/mxcubecore/configuration/alba_xaloc13/mini-diff.xml +++ b/mxcubecore/configuration/alba_xaloc13/mini-diff.xml @@ -1,49 +1,41 @@ - + bl13/eh/diff + + False + - - - - - - + + - - - - - - + - True + False - + {"x": 450,"y": 335} - - - {"actuator_name": "phiz", "position":-0.0175, "camera_axis":"y","direction": -1} {"fast": (1, 0), "slow": (0, -1)} True ("Transfer", "Centring", "Collect", "BeamView") - CurrentPhase - + CurrentPhase State + OmegaZReference + GoTransferPhase + GoSampleViewPhase State,CurrentPhase 0.2 diff --git a/mxcubecore/configuration/alba_xaloc13/mxcollect.xml b/mxcubecore/configuration/alba_xaloc13/mxcollect.xml index 7e41980336..fa66a2d723 100755 --- a/mxcubecore/configuration/alba_xaloc13/mxcollect.xml +++ b/mxcubecore/configuration/alba_xaloc13/mxcollect.xml @@ -1,12 +1,16 @@ - + + False + True + /beamlines/bl13/commissioning/latest_user_data_collection + - + - + @@ -19,15 +23,21 @@ - + - bl13/door/05 - ni660x_configure_collect - ni660x_unconfigure_collect + bl13/door/01 + ni660x_configure_collect_multi + ni660x_unconfigure_collect_multi + meshct + ascanct + + set_meas_conf + senv - position - position + position + position + position beamx beamy diff --git a/mxcubecore/configuration/alba_xaloc13/offline-processing.xml b/mxcubecore/configuration/alba_xaloc13/offline-processing.xml new file mode 100755 index 0000000000..ccac52d573 --- /dev/null +++ b/mxcubecore/configuration/alba_xaloc13/offline-processing.xml @@ -0,0 +1,9 @@ + + + /beamlines/bl13/sdm/production/processing_xaloc/templates + + + beamx + beamy + + diff --git a/mxcubecore/configuration/alba_xaloc13/omega.xml b/mxcubecore/configuration/alba_xaloc13/omega.xml index 778e57a44e..6e3bdb5edd 100755 --- a/mxcubecore/configuration/alba_xaloc13/omega.xml +++ b/mxcubecore/configuration/alba_xaloc13/omega.xml @@ -1,7 +1,8 @@ - + Omega omega Omega 45 500 + 0.0001 diff --git a/mxcubecore/configuration/alba_xaloc13/omegax.xml b/mxcubecore/configuration/alba_xaloc13/omegax.xml index ce16bdbae3..a7134716dc 100755 --- a/mxcubecore/configuration/alba_xaloc13/omegax.xml +++ b/mxcubecore/configuration/alba_xaloc13/omegax.xml @@ -1,7 +1,8 @@ - + Omega X omegax OmegaX + 0.0002 + + /beamlines/bl13/sdm/production/processing_xaloc/edna-mx/dozor/run_dozor.sh + True + + + + diff --git a/mxcubecore/configuration/alba_xaloc13/parallel-processing.xml b/mxcubecore/configuration/alba_xaloc13/parallel-processing.xml deleted file mode 100755 index c8b3deffa7..0000000000 --- a/mxcubecore/configuration/alba_xaloc13/parallel-processing.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - /pathToProcessingScript - True - diff --git a/mxcubecore/configuration/alba_xaloc13/photonshut.xml b/mxcubecore/configuration/alba_xaloc13/photonshut.xml index 45992f4876..fa9cbc6ed3 100755 --- a/mxcubecore/configuration/alba_xaloc13/photonshut.xml +++ b/mxcubecore/configuration/alba_xaloc13/photonshut.xml @@ -1,6 +1,6 @@ - + Photon Shutter bl13/ct/eps-plc-01 pshu - Open,Closed + Closed,Open diff --git a/mxcubecore/configuration/alba_xaloc13/pilatus.xml b/mxcubecore/configuration/alba_xaloc13/pilatus.xml index 6c233892f2..6a1f37cca0 100755 --- a/mxcubecore/configuration/alba_xaloc13/pilatus.xml +++ b/mxcubecore/configuration/alba_xaloc13/pilatus.xml @@ -1,27 +1,59 @@ - - + + PilatusDetector - - bl13/eh/pilatuslima - bl13/eh/pilatusspecific + + bl13/eh/pilatus3xlima DECTRIS - 6M_F - pilatus + Pilatus 3X 6M + Hybrid photon counting + cbf 0.172 0.172 - - 0.1 - 0.08 - 0.08,1000 - - 0.003 - - beamx - beamy - - Position + 2463 + 2527 + + 0.01 + 0.01 + 0.01,1000 + 0.00095 + + True + + prepareAcq + startAcq + abortAcq + stopAcq + reset + resetCommonHeader + resetFrameHeaders + setImageHeader + + saving_mode + saving_prefix + saving_directory + saving_format + saving_next_number + saving_header_delimiter + saving_statistics + ready_for_next_acq + + acq_nb_frames + acq_trigger_mode + acq_expo_time + acq_status + acq_status_fault_error + latency_time + + energy_threshold + threshold + cam_state + SendCamServerCmd + + beamx + beamy + Position diff --git a/mxcubecore/configuration/alba_xaloc13/queue.xml b/mxcubecore/configuration/alba_xaloc13/queue.xml index 9fd8ee2fe0..6aa2debcd0 100755 --- a/mxcubecore/configuration/alba_xaloc13/queue.xml +++ b/mxcubecore/configuration/alba_xaloc13/queue.xml @@ -1,3 +1,5 @@ + diff --git a/mxcubecore/configuration/alba_xaloc13/resolution.xml b/mxcubecore/configuration/alba_xaloc13/resolution.xml index 72102baa38..dc32a259c9 100755 --- a/mxcubecore/configuration/alba_xaloc13/resolution.xml +++ b/mxcubecore/configuration/alba_xaloc13/resolution.xml @@ -1,7 +1,6 @@ - + Resolution rescomp - Resolution - 45 - + resolution + Position diff --git a/mxcubecore/configuration/alba_xaloc13/sample-view.xml b/mxcubecore/configuration/alba_xaloc13/sample-view.xml new file mode 100644 index 0000000000..99df64ac7a --- /dev/null +++ b/mxcubecore/configuration/alba_xaloc13/sample-view.xml @@ -0,0 +1,13 @@ + + + + + + + + + + False + + (1, 1.5, 2.) + diff --git a/mxcubecore/configuration/alba_xaloc13/session.xml b/mxcubecore/configuration/alba_xaloc13/session.xml index 7d2da8a675..709160cc8d 100755 --- a/mxcubecore/configuration/alba_xaloc13/session.xml +++ b/mxcubecore/configuration/alba_xaloc13/session.xml @@ -1,27 +1,26 @@ - + ALBA - MX-XALOC - MX-XALOC + BL13 - XALOC + BL13 - XALOC cbf '04' - - /tmp - + RAW_DATA /tmp - - - - + PROCESSED_DATA /beamlines/ispyb/bl13/ + + bl13/door/05 + senv + diff --git a/mxcubecore/configuration/alba_xaloc13/slowshut.xml b/mxcubecore/configuration/alba_xaloc13/slowshut.xml index 4a2ade9600..569c2bdeec 100755 --- a/mxcubecore/configuration/alba_xaloc13/slowshut.xml +++ b/mxcubecore/configuration/alba_xaloc13/slowshut.xml @@ -1,4 +1,4 @@ - + Slow Shutter bl13/ct/eps-plc-01 slowshu diff --git a/mxcubecore/configuration/alba_xaloc13/supervisor.xml b/mxcubecore/configuration/alba_xaloc13/supervisor.xml index 3a42d65bbe..548f4d186c 100755 --- a/mxcubecore/configuration/alba_xaloc13/supervisor.xml +++ b/mxcubecore/configuration/alba_xaloc13/supervisor.xml @@ -1,4 +1,4 @@ - + Beamline Supervisor bl13/eh/supervisor DetCoverOpen @@ -9,4 +9,8 @@ GoTransferPhase GoSampleViewPhase GoBeamViewPhase + + + ("Transfer", "Centring", "Collect") + diff --git a/mxcubecore/configuration/alba_xaloc13/transmission.xml b/mxcubecore/configuration/alba_xaloc13/transmission.xml index ceeb452222..41c71451b7 100755 --- a/mxcubecore/configuration/alba_xaloc13/transmission.xml +++ b/mxcubecore/configuration/alba_xaloc13/transmission.xml @@ -1,4 +1,4 @@ - + Transmission motor/eh_mbattransmot_ctrl/1 Position diff --git a/mxcubecore/configuration/alba_xaloc13/wavelength_motor.xml b/mxcubecore/configuration/alba_xaloc13/wavelength_motor.xml index 270452d1fc..c15ab8197c 100755 --- a/mxcubecore/configuration/alba_xaloc13/wavelength_motor.xml +++ b/mxcubecore/configuration/alba_xaloc13/wavelength_motor.xml @@ -1,7 +1,8 @@ - + Wavelength wavelength wavelength + 0.00002 45 diff --git a/mxcubecore/configuration/alba_xaloc13/xml-rpc-server.xml b/mxcubecore/configuration/alba_xaloc13/xml-rpc-server.xml index 3555534309..5ed34f0f69 100755 --- a/mxcubecore/configuration/alba_xaloc13/xml-rpc-server.xml +++ b/mxcubecore/configuration/alba_xaloc13/xml-rpc-server.xml @@ -9,6 +9,7 @@ 8000 + False @@ -17,7 +18,7 @@ - - - + + + diff --git a/mxcubecore/configuration/alba_xaloc13/zoom-auto-brightness.xml b/mxcubecore/configuration/alba_xaloc13/zoom-auto-brightness.xml deleted file mode 100755 index 4df2b9f15b..0000000000 --- a/mxcubecore/configuration/alba_xaloc13/zoom-auto-brightness.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/mxcubecore/configuration/alba_xaloc13/zoom.xml b/mxcubecore/configuration/alba_xaloc13/zoom.xml deleted file mode 100755 index a4cc3c2e3e..0000000000 --- a/mxcubecore/configuration/alba_xaloc13/zoom.xml +++ /dev/null @@ -1,11 +0,0 @@ - - Zoom - ioregister/eh_zoom_tangoior_ctrl/1 - zoom - Zoom - Value - State - Labels - 200 - 0.001 -