Source code for mxcubecore.HardwareObjects.ALBA.ALBACollect

#  Project name: 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 <http://www.gnu.org/licenses/>.

"""
ALBACollect
"""

import logging
import os
import sys
import time

import gevent

from mxcubecore import HardwareRepository as HWR
from mxcubecore.HardwareObjects.abstract.AbstractCollect import AbstractCollect
from mxcubecore.TaskUtils import task

__author__ = "Vicente Rey Bakaikoa"
__credits__ = ["MXCuBE collaboration"]
__version__ = "2.2."


[docs]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
[docs] 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: self.log.exception("") 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,))
[docs] def data_collection_hook(self): """Main collection hook""" self.log.info("Running ALBA data collection hook") self.log.info(" -- wait for devices to finish moving --") self.log.info(" + wait for resolution...") HWR.beamline.resolution.wait_end_of_move() self.log.info(" + wait for detector distance...") HWR.beamline.detector.wait_move_distance_done() self.log.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"] self.log.debug("Running a collect (exp_type=%s)" % exp_type) if exp_type == "Characterization": self.log.debug("Running a collect (CHARACTERIZATION)") elif exp_type == "Helical": self.log.debug("Running a helical collection") self.log.debug(" helical positions are: %s" % str(self.helical_positions)) hpos = self.helical_positions self.log.debug( " phiy from %3.4f to %3.4f" % (hpos[0], hpos[4]) ) self.log.debug( " phiz from %3.4f to %3.4f" % (hpos[1], hpos[5]) ) self.log.debug( " sampx from %3.4f to %3.4f" % (hpos[2], hpos[6]) ) self.log.debug( " sampy from %3.4f to %3.4f" % (hpos[3], hpos[7]) ) elif exp_type == "Mesh": self.log.debug("Running a raster collection ()") self.log.debug(" number of lines are: %s" % self.mesh_num_lines) self.log.debug(" total nb of frames: %s" % self.mesh_total_nb_frames) self.log.debug(" mesh range : %s" % self.mesh_range) self.log.debug(" mesh center : %s" % self.mesh_center) else: self.log.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"] self.log.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 # self.log.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): self.log.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) self.log.info( " Waiting for diffractometer to be ready. Now %s" % str(HWR.beamline.diffractometer.current_state) ) HWR.beamline.diffractometer.wait_device_ready(timeout=10) self.log.info(" diffractometer is now ready.") # go to collect phase if not self.is_collect_phase(): self.log.info(" Not in collect phase. Asking supervisor to go") self.log.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) self.log.info(" prepare detector was not ok.") self.write_image_headers(start_angle) self.log.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) ) self.log.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 self.log.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) self.log.info( "Moving omega finished at %s" % HWR.beamline.diffractometer.omega.get_value() ) # program omega speed depending on exposure time self.log.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" # NBNB TODO check if get_beam_position() (should be pixels) # matches beamx, beamy (should be mm) 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() self.log.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: self.log.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) self.log.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) self.log.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) # self.log.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): self.log.debug("sending supervisor to collect phase") self.supervisor_hwobj.go_collect() self.log.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: self.log.debug("timeout sending supervisor to collect phase") break gevent.sleep(0.5) self.log.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): self.log.debug("sending supervisor to sample view phase") self.supervisor_hwobj.go_sample_view() self.log.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: self.log.debug("timeout sending supervisor to sample view phase") break gevent.sleep(0.5) self.log.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): self.log.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()
[docs] 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()
[docs] def open_detector_cover(self): self.supervisor_hwobj.open_detector_cover()
[docs] 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
[docs] def close_fast_shutter(self): HWR.beamline.fast_shutter.cmdOut()
[docs] def close_safety_shutter(self): # we will not close safety shutter during collections pass
[docs] def close_detector_cover(self): # we will not close detcover during collections # self.supervisor.close_detector_cover() pass
[docs] 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"], ]
[docs] 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) self.log.debug(" - snapshot saved to %s" % filename) @task def move_motors(self, motor_position_dict): """ Descript. : """ HWR.beamline.diffractometer.move_motors(motor_position_dict)
[docs] 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 )
[docs] 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
[docs] 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: self.log.exception("") return {}
[docs] def get_slit_gaps(self): """ Descript. : """ if HWR.beamline.beam is not None: return HWR.beamline.beam.get_slits_gap() return None, None
[docs] def get_beam_shape(self): """ Descript. : """ if HWR.beamline.beam is not None: return HWR.beamline.beam.get_beam_shape()
[docs] def get_machine_current(self): """ Descript. : """ if HWR.beamline.machine_info: return HWR.beamline.machine_info.get_current() else: return 0
[docs] def get_machine_message(self): """ Descript. : """ if HWR.beamline.machine_info: return HWR.beamline.machine_info.get_message() else: return ""
[docs] 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 ""
[docs] 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())