Exemplo n.º 1
0
class ESRFMultiCollect(AbstractMultiCollect, HardwareObject):
    def __init__(self, name, detector, tunable_bl):
        AbstractMultiCollect.__init__(self)
        HardwareObject.__init__(self, name)
        self._detector = detector
        self._tunable_bl = tunable_bl
        self._centring_status = None
        self._metadataClient = None

    def execute_command(self, command_name, *args, **kwargs): 
      wait = kwargs.get("wait", True)
      cmd_obj = self.getCommandObject(command_name)
      return cmd_obj(*args, wait=wait)
        
    def init(self):
        self.setControlObjects(diffractometer = self.getObjectByRole("diffractometer"),
                               sample_changer = self.getObjectByRole("sample_changer"),
                               lims = self.getObjectByRole("dbserver"),
                               safety_shutter = self.getObjectByRole("safety_shutter"),
                               machine_current = self.getObjectByRole("machine_current"),
                               cryo_stream = self.getObjectByRole("cryo_stream"),
                               energy = self.getObjectByRole("energy"),
                               resolution = self.getObjectByRole("resolution"),
                               detector_distance = self.getObjectByRole("detector_distance"),
                               transmission = self.getObjectByRole("transmission"),
                               undulators = self.getObjectByRole("undulators"),
                               flux = self.getObjectByRole("flux"),
                               detector = self.getObjectByRole("detector"),
                               beam_info = self.getObjectByRole("beam_info"))

        try:
          undulators = self["undulator"]
        except IndexError:
          undulators = []

        self.setBeamlineConfiguration(synchrotron_name = "ESRF",
                                      directory_prefix = self.getProperty("directory_prefix"),
                                      default_exposure_time = self.bl_control.detector.getProperty("default_exposure_time"),
                                      minimum_exposure_time = self.bl_control.detector.getProperty("minimum_exposure_time"),
                                      detector_fileext = self.bl_control.detector.getProperty("file_suffix"),
                                      detector_type = self.bl_control.detector.getProperty("type"),
                                      detector_manufacturer = self.bl_control.detector.getProperty("manufacturer"),
                                      detector_model = self.bl_control.detector.getProperty("model"),
                                      detector_px = self.bl_control.detector.getProperty("px"),
                                      detector_py = self.bl_control.detector.getProperty("py"),
                                      undulators = undulators,
                                      focusing_optic = self.getProperty('focusing_optic'),
                                      monochromator_type = self.getProperty('monochromator'),
                                      beam_divergence_vertical = self.bl_control.beam_info.getProperty('beam_divergence_vertical'),
                                      beam_divergence_horizontal = self.bl_control.beam_info.getProperty('beam_divergence_horizontal'),     
                                      polarisation = self.getProperty('polarisation'),
                                      input_files_server = self.getProperty("input_files_server"))
  
        self._detector.addCommand = self.addCommand
        self._detector.addChannel = self.addChannel
        self._detector.getCommandObject = self.getCommandObject
        self._detector.getChannelObject = self.getChannelObject
        self._detector.execute_command = self.execute_command
        self._detector.init(self.bl_control.detector, self)
        self._tunable_bl.bl_control = self.bl_control

        self.emit("collectConnected", (True,))
        self.emit("collectReady", (True, ))

    @task
    def take_crystal_snapshots(self, number_of_snapshots):
        self.bl_control.diffractometer.takeSnapshots(number_of_snapshots, wait=True)

    @task
    def data_collection_hook(self, data_collect_parameters):
        if self._metadataClient is None:
            self._metadataClient = MXCuBEMetadataClient(self)
        self._metadataClient.start(data_collect_parameters)
        
 
    @task
    def data_collection_end_hook(self, data_collect_parameters):
        self._metadataClient.end(data_collect_parameters)

    def do_prepare_oscillation(self, start, end, exptime, npass):
        return self.execute_command("prepare_oscillation", start, end, exptime, npass)
    
    @task
    def oscil(self, start, end, exptime, npass):
      if math.fabs(end-start) < 1E-4:
        self.open_fast_shutter()
        time.sleep(exptime)
        self.close_fast_shutter()
      else:
        return self.execute_command("do_oscillation", start, end, exptime, npass)
    
    @task
    def set_transmission(self, transmission_percent):
        self.bl_control.transmission.setTransmission(transmission_percent)


    def set_wavelength(self, wavelength):
        return self._tunable_bl.set_wavelength(wavelength)


    def set_energy(self, energy):
        return self._tunable_bl.set_energy(energy)


    @task
    def set_resolution(self, new_resolution):
        return
        

    @task
    def move_detector(self, detector_distance):
        return


    @task
    def data_collection_cleanup(self):
        self.close_fast_shutter()


    @task
    def close_fast_shutter(self):
        self.execute_command("close_fast_shutter")


    @task
    def open_fast_shutter(self):
        self.execute_command("open_fast_shutter")

        
    @task
    def move_motors(self, motor_position_dict):
        for motor in motor_position_dict.keys(): #iteritems():
            position = motor_position_dict[motor]
            if isinstance(motor, str) or isinstance(motor, unicode):
                # find right motor object from motor role in diffractometer obj.
                motor_role = motor
                motor = self.bl_control.diffractometer.getDeviceByRole(motor_role)
                del motor_position_dict[motor_role]
                if motor is None:
                  continue
                motor_position_dict[motor]=position

            logging.getLogger("HWR").info("Moving motor '%s' to %f", motor.getMotorMnemonic(), position)
            motor.move(position)

        while any([motor.motorIsMoving() for motor in motor_position_dict.iterkeys()]):
            logging.getLogger("HWR").info("Waiting for end of motors motion")
            time.sleep(0.02)  


    @task
    def open_safety_shutter(self):
        self.bl_control.safety_shutter.openShutter()
        while self.bl_control.safety_shutter.getShutterState() == 'closed':
          time.sleep(0.1)


    def safety_shutter_opened(self):
        return self.bl_control.safety_shutter.getShutterState() == "opened"


    @task
    def close_safety_shutter(self):
        self.bl_control.safety_shutter.closeShutter()
        while self.bl_control.safety_shutter.getShutterState() == 'opened':
          time.sleep(0.1)


    @task
    def prepare_intensity_monitors(self):
        self.execute_command("adjust_gains")


    def prepare_acquisition(self, take_dark, start, osc_range, exptime, npass, number_of_images, comment=""):
        energy = self._tunable_bl.getCurrentEnergy()
        return self._detector.prepare_acquisition(take_dark, start, osc_range, exptime, npass, number_of_images, comment, energy)


    def set_detector_filenames(self, frame_number, start, filename, jpeg_full_path, jpeg_thumbnail_full_path):
        return self._detector.set_detector_filenames(frame_number, start, filename, jpeg_full_path, jpeg_thumbnail_full_path)


    def prepare_oscillation(self, start, osc_range, exptime, npass):
        return self._detector.prepare_oscillation(start, osc_range, exptime, npass)

    
    def do_oscillation(self, start, end, exptime, npass):
        return self._detector.do_oscillation(start, end, exptime, npass)
    
  
    def start_acquisition(self, exptime, npass, first_frame):
        return self._detector.start_acquisition(exptime, npass, first_frame)
    
      
    def write_image(self, last_frame):
        return self._detector.write_image(last_frame)


    def last_image_saved(self):
        return self._detector.last_image_saved()

    def stop_acquisition(self):
        return self._detector.stop_acquisition()
        
      
    def reset_detector(self):
        return self._detector.reset_detector()
        

    def prepare_input_files(self, files_directory, prefix, run_number, process_directory):
        i = 1

        while True:
          xds_input_file_dirname = "xds_%s_run%s_%d" % (prefix, run_number, i)
          autoprocessing_input_file_dirname = "autoprocessing_%s_run%s_%d" % (prefix, run_number, i)
          autoprocessing_directory = os.path.join(process_directory, autoprocessing_input_file_dirname)

          if not os.path.exists(autoprocessing_directory):
            break

          i+=1

        mosflm_input_file_dirname = "mosflm_%s_run%s_%d" % (prefix, run_number, i)

        hkl2000_dirname = "hkl2000_%s_run%s_%d" % (prefix, run_number, i)

        self.raw_data_input_file_dir = os.path.join(files_directory, "process", xds_input_file_dirname)
        self.mosflm_raw_data_input_file_dir = os.path.join(files_directory, "process", mosflm_input_file_dirname)
        self.raw_hkl2000_dir = os.path.join(files_directory, "process", hkl2000_dirname)

        for dir in (self.raw_data_input_file_dir, self.mosflm_raw_data_input_file_dir, self.raw_hkl2000_dir, autoprocessing_directory):
          self.create_directories(dir)
          logging.info("Creating processing input file directory: %s", dir)
          os.chmod(dir, 0777)
 
        try: 
          try: 
              os.symlink(files_directory, os.path.join(process_directory, "links"))
          except os.error, e:
              if e.errno != errno.EEXIST:
                  raise
        except:
            logging.exception("Could not create processing file directory")

        return autoprocessing_directory, "", ""


    @task
    def write_input_files(self, collection_id):
        # assumes self.xds_directory and self.mosflm_directory are valid
        conn = httplib.HTTPConnection(self.bl_config.input_files_server)

        # hkl input files 
        input_file_dir = self.raw_hkl2000_dir
        file_prefix = "../.."
        hkl_file_path = os.path.join(input_file_dir, "def.site")
        conn.request("GET", "/def.site/%d?basedir=%s" % (collection_id, file_prefix))
        hkl_file = open(hkl_file_path, "w")
        r = conn.getresponse()

        if r.status != 200:
            logging.error("Could not create hkl input file")
        else:
            hkl_file.write(r.read())
        hkl_file.close()
        os.chmod(hkl_file_path, 0666)

        for input_file_dir, file_prefix in ((self.raw_data_input_file_dir, "../.."), (self.xds_directory, "../links")): 
            xds_input_file = os.path.join(input_file_dir, "XDS.INP")
            conn.request("GET", "/xds.inp/%d?basedir=%s" % (collection_id, file_prefix))
            xds_file = open(xds_input_file, "w")
            r = conn.getresponse()
            if r.status != 200:
                logging.error("Could not create xds input file")
            else:
                xds_file.write(r.read())
            xds_file.close()
            os.chmod(xds_input_file, 0666)

        input_file_dir = self.mosflm_raw_data_input_file_dir 
        file_prefix = "../.." 
	    mosflm_input_file = os.path.join(input_file_dir, "mosflm.inp")
        conn.request("GET", "/mosflm.inp/%d?basedir=%s" % (collection_id, file_prefix))
        mosflm_file = open(mosflm_input_file, "w")
        mosflm_file.write(conn.getresponse().read()) 
        mosflm_file.close()
        os.chmod(mosflm_input_file, 0666)
        
        # also write input file for STAC
        for stac_om_input_file_name, stac_om_dir in (("xds.descr", self.xds_directory),
                                                     ("mosflm.descr", self.mosflm_raw_data_input_file_dir),
                                                     ("xds.descr", self.raw_data_input_file_dir)):
          stac_om_input_file = os.path.join(stac_om_dir, stac_om_input_file_name)
          conn.request("GET", "/stac.descr/%d" % collection_id)
          stac_om_file = open(stac_om_input_file, "w")
          stac_template = conn.getresponse().read()
          if stac_om_input_file_name.startswith("xds"):
            om_type="xds"
            if stac_om_dir == self.raw_data_input_file_dir:
              om_filename=os.path.join(stac_om_dir, "CORRECT.LP")
            else:
              om_filename=os.path.join(stac_om_dir, "xds_fastproc", "CORRECT.LP")
          else:
            om_type="mosflm"
            om_filename=os.path.join(stac_om_dir, "bestfile.par")
       
          stac_om_file.write(stac_template.format(omfilename=om_filename, omtype=om_type, 
                             phi=self.bl_control.diffractometer.phiMotor.getPosition(), 
                             sampx=self.bl_control.diffractometer.sampleXMotor.getPosition(), 
                             sampy=self.bl_control.diffractometer.sampleYMotor.getPosition(), 
                             phiy=self.bl_control.diffractometer.phiyMotor.getPosition()))
          stac_om_file.close()
          os.chmod(stac_om_input_file, 0666)
Exemplo n.º 2
0
class ESRFMultiCollect(AbstractMultiCollect, HardwareObject):
    def __init__(self, name, detector, tunable_bl):
        AbstractMultiCollect.__init__(self)
        HardwareObject.__init__(self, name)
        self._detector = detector
        self._tunable_bl = tunable_bl
        self._centring_status = None
        self._metadataClient = None
        self.__mesh_steps = None
        self._mesh_range = None

    @property
    def _mesh_steps(self):
        return self.__mesh_steps

    @_mesh_steps.setter
    def _mesh_steps(self, steps):
        self.__mesh_steps = steps
        self._detector._mesh_steps = steps

    def execute_command(self, command_name, *args, **kwargs):
        wait = kwargs.get("wait", True)
        cmd_obj = self.getCommandObject(command_name)
        return cmd_obj(*args, wait=wait)

    def init(self):
        self.setControlObjects(
            diffractometer=self.getObjectByRole("diffractometer"),
            sample_changer=self.getObjectByRole("sample_changer"),
            lims=self.getObjectByRole("dbserver"),
            safety_shutter=self.getObjectByRole("safety_shutter"),
            machine_current=self.getObjectByRole("machine_current"),
            cryo_stream=self.getObjectByRole("cryo_stream"),
            energy=self.getObjectByRole("energy"),
            resolution=self.getObjectByRole("resolution"),
            detector_distance=self.getObjectByRole("detector_distance"),
            transmission=self.getObjectByRole("transmission"),
            undulators=self.getObjectByRole("undulators"),
            flux=self.getObjectByRole("flux"),
            detector=self.getObjectByRole("detector"),
            beam_info=self.getObjectByRole("beam_info"))

        try:
            undulators = self["undulator"]
        except IndexError:
            undulators = []

        self.setBeamlineConfiguration(
            synchrotron_name="ESRF",
            directory_prefix=self.getProperty("directory_prefix"),
            default_exposure_time=self.bl_control.detector.getProperty(
                "default_exposure_time"),
            minimum_exposure_time=self.bl_control.detector.getProperty(
                "minimum_exposure_time"),
            detector_fileext=self.bl_control.detector.getProperty(
                "file_suffix"),
            detector_type=self.bl_control.detector.getProperty("type"),
            detector_manufacturer=self.bl_control.detector.getProperty(
                "manufacturer"),
            detector_model=self.bl_control.detector.getProperty("model"),
            detector_px=self.bl_control.detector.getProperty("px"),
            detector_py=self.bl_control.detector.getProperty("py"),
            undulators=undulators,
            focusing_optic=self.getProperty('focusing_optic'),
            monochromator_type=self.getProperty('monochromator'),
            beam_divergence_vertical=self.bl_control.beam_info.getProperty(
                'beam_divergence_vertical'),
            beam_divergence_horizontal=self.bl_control.beam_info.getProperty(
                'beam_divergence_horizontal'),
            polarisation=self.getProperty('polarisation'),
            maximum_phi_speed=self.getProperty('maximum_phi_speed'),
            minimum_phi_oscillation=self.getProperty(
                'minimum_phi_oscillation'),
            input_files_server=self.getProperty("input_files_server"))

        self._detector.addCommand = self.addCommand
        self._detector.addChannel = self.addChannel
        self._detector.getCommandObject = self.getCommandObject
        self._detector.getChannelObject = self.getChannelObject
        self._detector.execute_command = self.execute_command
        self._detector.init(self.bl_control.detector, self)
        self._tunable_bl.bl_control = self.bl_control

        self.emit("collectConnected", (True, ))
        self.emit("collectReady", (True, ))

    @task
    def take_crystal_snapshots(self, number_of_snapshots):
        self.bl_control.diffractometer.takeSnapshots(number_of_snapshots,
                                                     wait=True)

    @task
    def data_collection_hook(self, data_collect_parameters):
        if self._metadataClient is None:
            self._metadataClient = MXCuBEMetadataClient(self)
        self._metadataClient.start(data_collect_parameters)

    @task
    def data_collection_end_hook(self, data_collect_parameters):
        self._metadataClient.end(data_collect_parameters)

    def do_prepare_oscillation(self, start, end, exptime, npass):
        return self.execute_command("prepare_oscillation", start, end, exptime,
                                    npass)

    @task
    def oscil(self, start, end, exptime, npass, wait=False):
        if math.fabs(end - start) < 1E-4:
            self.open_fast_shutter()
            time.sleep(exptime)
            self.close_fast_shutter()
        else:
            return self.execute_command("do_oscillation", start, end, exptime,
                                        npass)

    @task
    def set_transmission(self, transmission_percent):
        self.bl_control.transmission.setTransmission(transmission_percent)

    def set_wavelength(self, wavelength):
        return self._tunable_bl.set_wavelength(wavelength)

    def set_energy(self, energy):
        return self._tunable_bl.set_energy(energy)

    @task
    def set_resolution(self, new_resolution):
        return

    @task
    def move_detector(self, detector_distance):
        return

    @task
    def data_collection_cleanup(self):
        try:
            self.stop_oscillation()
        finally:
            self.close_fast_shutter()

    @task
    def close_fast_shutter(self):
        self.execute_command("close_fast_shutter")

    @task
    def open_fast_shutter(self):
        self.execute_command("open_fast_shutter")

    @task
    def move_motors(self, motor_position_dict):
        for motor in motor_position_dict.keys():  # iteritems():
            position = motor_position_dict[motor]
            if isinstance(motor, str) or isinstance(motor, unicode):
                # find right motor object from motor role in diffractometer obj.
                motor_role = motor
                motor = self.bl_control.diffractometer.getDeviceByRole(
                    motor_role)
                del motor_position_dict[motor_role]
                if motor is None:
                    continue
                motor_position_dict[motor] = position

            logging.getLogger("HWR").info("Moving motor '%s' to %f",
                                          motor.getMotorMnemonic(), position)
            motor.move(position)

        while any([
                motor.motorIsMoving()
                for motor in motor_position_dict.iterkeys()
        ]):
            logging.getLogger("HWR").info("Waiting for end of motors motion")
            time.sleep(0.02)

    @task
    def open_safety_shutter(self):
        self.bl_control.safety_shutter.openShutter()
        while self.bl_control.safety_shutter.getShutterState() == 'closed':
            time.sleep(0.1)

    def safety_shutter_opened(self):
        return self.bl_control.safety_shutter.getShutterState() == "opened"

    @task
    def close_safety_shutter(self):
        self.bl_control.safety_shutter.closeShutter()
        while self.bl_control.safety_shutter.getShutterState() == 'opened':
            time.sleep(0.1)

    @task
    def prepare_intensity_monitors(self):
        try:
            self.execute_command("adjust_gains")
        except AttributeError:
            pass

    def prepare_acquisition(self,
                            take_dark,
                            start,
                            osc_range,
                            exptime,
                            npass,
                            number_of_images,
                            comment="",
                            trigger_mode=None):
        energy = self._tunable_bl.getCurrentEnergy()
        return self._detector.prepare_acquisition(take_dark, start, osc_range,
                                                  exptime, npass,
                                                  number_of_images, comment,
                                                  energy, trigger_mode)

    def set_detector_filenames(self, frame_number, start, filename,
                               jpeg_full_path, jpeg_thumbnail_full_path):
        return self._detector.set_detector_filenames(frame_number, start,
                                                     filename, jpeg_full_path,
                                                     jpeg_thumbnail_full_path)

    def prepare_oscillation(self, start, osc_range, exptime, npass):
        return self._detector.prepare_oscillation(start, osc_range, exptime,
                                                  npass)

    def do_oscillation(self, start, end, exptime, npass):
        return self._detector.do_oscillation(start, end, exptime, npass)

    def stop_oscillation(self):
        pass

    def start_acquisition(self, exptime, npass, first_frame):
        return self._detector.start_acquisition(exptime, npass, first_frame)

    def write_image(self, last_frame):
        return self._detector.write_image(last_frame)

    def last_image_saved(self):
        return self._detector.last_image_saved()

    def stop_acquisition(self):
        return self._detector.stop_acquisition()

    def reset_detector(self):
        return self._detector.reset_detector()

    def prepare_input_files(self, files_directory, prefix, run_number,
                            process_directory):
        i = 1

        while True:
            xds_input_file_dirname = "xds_%s_run%s_%d" % (prefix, run_number,
                                                          i)
            autoprocessing_input_file_dirname = "autoprocessing_%s_run%s_%d" % (
                prefix, run_number, i)
            autoprocessing_directory = os.path.join(
                process_directory, autoprocessing_input_file_dirname)

            if not os.path.exists(autoprocessing_directory):
                break

            i += 1

        mosflm_input_file_dirname = "mosflm_%s_run%s_%d" % (prefix, run_number,
                                                            i)

        hkl2000_dirname = "hkl2000_%s_run%s_%d" % (prefix, run_number, i)

        self.raw_data_input_file_dir = os.path.join(files_directory, "process",
                                                    xds_input_file_dirname)
        self.mosflm_raw_data_input_file_dir = os.path.join(
            files_directory, "process", mosflm_input_file_dirname)
        self.raw_hkl2000_dir = os.path.join(files_directory, "process",
                                            hkl2000_dirname)

        for dir in (self.raw_data_input_file_dir,
                    self.mosflm_raw_data_input_file_dir, self.raw_hkl2000_dir,
                    autoprocessing_directory):
            self.create_directories(dir)
            logging.info("Creating processing input file directory: %s", dir)
            os.chmod(dir, 0777)

        try:
            try:
                os.symlink(files_directory,
                           os.path.join(process_directory, "links"))
            except os.error, e:
                if e.errno != errno.EEXIST:
                    raise
        except:
            logging.exception("Could not create processing file directory")

        return autoprocessing_directory, "", ""

    @task
    def write_input_files(self, collection_id):
        # assumes self.xds_directory and self.mosflm_directory are valid
        conn = httplib.HTTPConnection(self.bl_config.input_files_server)

        # hkl input files
        input_file_dir = self.raw_hkl2000_dir
        file_prefix = "../.."
        hkl_file_path = os.path.join(input_file_dir, "def.site")

        conn.request("GET",
                     "/def.site/%d?basedir=%s" % (collection_id, file_prefix))
        hkl_file = open(hkl_file_path, "w")
        r = conn.getresponse()

        if r.status != 200:
            logging.error("Could not create hkl input file")
        else:
            hkl_file.write(r.read())
        hkl_file.close()
        os.chmod(hkl_file_path, 0666)

        for input_file_dir, file_prefix in ((self.raw_data_input_file_dir,
                                             "../.."), (self.xds_directory,
                                                        "../links")):
            xds_input_file = os.path.join(input_file_dir, "XDS.INP")
            conn.request(
                "GET", "/xds.inp/%d?basedir=%s" % (collection_id, file_prefix))
            xds_file = open(xds_input_file, "w")
            r = conn.getresponse()
            if r.status != 200:
                logging.error("Could not create xds input file")
            else:
                xds_file.write(r.read())
            xds_file.close()
            os.chmod(xds_input_file, 0666)

        input_file_dir = self.mosflm_raw_data_input_file_dir
        file_prefix = "../.."
        mosflm_input_file = os.path.join(input_file_dir, "mosflm.inp")
        conn.request(
            "GET", "/mosflm.inp/%d?basedir=%s" % (collection_id, file_prefix))
        mosflm_file = open(mosflm_input_file, "w")
        mosflm_file.write(conn.getresponse().read())
        mosflm_file.close()
        os.chmod(mosflm_input_file, 0666)

        # also write input file for STAC
        for stac_om_input_file_name, stac_om_dir in (
            ("xds.descr", self.xds_directory),
            ("mosflm.descr", self.mosflm_raw_data_input_file_dir),
            ("xds.descr", self.raw_data_input_file_dir)):
            stac_om_input_file = os.path.join(stac_om_dir,
                                              stac_om_input_file_name)
            conn.request("GET", "/stac.descr/%d" % collection_id)
            stac_om_file = open(stac_om_input_file, "w")
            stac_template = conn.getresponse().read()
            if stac_om_input_file_name.startswith("xds"):
                om_type = "xds"
                if stac_om_dir == self.raw_data_input_file_dir:
                    om_filename = os.path.join(stac_om_dir, "CORRECT.LP")
                else:
                    om_filename = os.path.join(stac_om_dir, "xds_fastproc",
                                               "CORRECT.LP")
            else:
                om_type = "mosflm"
                om_filename = os.path.join(stac_om_dir, "bestfile.par")

            stac_om_file.write(
                stac_template.format(
                    omfilename=om_filename,
                    omtype=om_type,
                    phi=self.bl_control.diffractometer.phiMotor.getPosition(),
                    sampx=self.bl_control.diffractometer.sampleXMotor.
                    getPosition(),
                    sampy=self.bl_control.diffractometer.sampleYMotor.
                    getPosition(),
                    phiy=self.bl_control.diffractometer.phiyMotor.getPosition(
                    )))
            stac_om_file.close()
            os.chmod(stac_om_input_file, 0666)

    def get_wavelength(self):
        return self._tunable_bl.get_wavelength()

    def get_detector_distance(self):
        return

    def get_resolution(self):
        return self.bl_control.resolution.getPosition()

    def get_transmission(self):
        return self.bl_control.transmission.getAttFactor()

    def get_undulators_gaps(self):
        all_gaps = {'Unknown': None}
        _gaps = {}
        try:
            _gaps = self.bl_control.undulators.getUndulatorGaps()
        except:
            logging.getLogger("HWR").exception("Could not get undulator gaps")
        all_gaps.clear()
        for key in _gaps:
            if '_Position' in key:
                nkey = key[:-9]
                all_gaps[nkey] = _gaps[key]
            else:
                all_gaps = _gaps
        return all_gaps

    def get_resolution_at_corner(self):
        return self.execute_command("get_resolution_at_corner")

    def get_beam_size(self):
        return (self.execute_command("get_beam_size_x"),
                self.execute_command("get_beam_size_y"))

    def get_slit_gaps(self):
        return (self.execute_command("get_slit_gap_h"),
                self.execute_command("get_slit_gap_v"))

    def get_beam_shape(self):
        return self.execute_command("get_beam_shape")

    def get_measured_intensity(self):
        try:
            val = self.getChannelObject("image_intensity").getValue()
            return float(val)
        except:
            return 0

    def get_machine_current(self):
        if self.bl_control.machine_current:
            try:
                return self.bl_control.machine_current.getCurrent()
            except:
                return -1
        else:
            return 0

    def get_machine_message(self):
        if self.bl_control.machine_current:
            return self.bl_control.machine_current.getMessage()
        else:
            return ''

    def get_machine_fill_mode(self):
        if self.bl_control.machine_current:
            return self.bl_control.machine_current.getFillMode()
        else:
            ''

    def get_cryo_temperature(self):
        while True:
            logging.info("Reading cryostream temperature")
            try:
                T = self.bl_control.cryo_stream.getTemperature()
            except Exception:
                time.sleep(0.1)
                continue
            else:
                return T

    def getCurrentEnergy(self):
        return self._tunable_bl.getCurrentEnergy()

    def get_beam_centre(self):
        return (self.execute_command("get_beam_centre_x"),
                self.execute_command("get_beam_centre_y"))

    def getBeamlineConfiguration(self, *args):
        # TODO: change this to stop using a dictionary at the other end
        return self.bl_config._asdict()

    def isConnected(self):
        return True

    def isReady(self):
        return True

    def sampleChangerHO(self):
        return self.bl_control.sample_changer

    def diffractometer(self):
        return self.bl_control.diffractometer

    def dbServerHO(self):
        return self.bl_control.lims

    def sanityCheck(self, collect_params):
        return

    def setBrick(self, brick):
        return

    def directoryPrefix(self):
        return self.bl_config.directory_prefix

    def store_image_in_lims(self, frame, first_frame, last_frame):
        if isinstance(self._detector, CcdDetector):
            return True

        if isinstance(self._detector, PixelDetector):
            if first_frame or last_frame:
                return True

    def get_flux(self):
        return self.bl_control.flux.getCurrentFlux()

    @task
    def generate_image_jpeg(self, filename, jpeg_path, jpeg_thumbnail_path):
        directories = filename.split(os.path.sep)
        try:
            if directories[1] == "data" and directories[2] == "gz":
                if directories[3] == "visitor":
                    proposal = directories[4]
                    beamline = directories[5]
                elif directories[4] == "inhouse":
                    proposal = directories[5]
                    beamline = directories[3]
                else:
                    proposal = "unknown"
                    beamline = "unknown"

            elif directories[2] == 'visitor':
                beamline = directories[4]
                proposal = directories[3]
            else:
                beamline = directories[2]
                proposal = directories[4]
        except:
            beamline = "unknown"
            proposal = "unknown"
        host, port = self.getProperty("bes_jpeg_hostport").split(":")
        conn = httplib.HTTPConnection(host, int(port))

        params = urllib.urlencode({
            "image_path": filename,
            "jpeg_path": jpeg_path,
            "jpeg_thumbnail_path": jpeg_thumbnail_path,
            "initiator": beamline,
            "externalRef": proposal,
            "reuseCase": "true"
        })
        conn.request("POST",
                     "/BES/bridge/rest/processes/CreateThumbnails/RUN?%s" %
                     params,
                     headers={"Accept": "text/plain"})
        r = conn.getresponse()

    """
    getOscillation
        Description: Returns the parameters (and results) of an oscillation.
        Type       : method
        Arguments  : oscillation_id (int; the oscillation id, the last parameters of the collectOscillationStarted
                                     signal)
        Returns    : tuple; (blsampleid,barcode,location,parameters)
    """

    def getOscillation(self, oscillation_id):
        return self.oscillations_history[oscillation_id - 1]

    def sampleAcceptCentring(self, accepted, centring_status):
        self.sample_centring_done(accepted, centring_status)

    def setCentringStatus(self, centring_status):
        self._centring_status = centring_status

    """
    getOscillations
        Description: Returns the history of oscillations for a session
        Type       : method
        Arguments  : session_id (int; the session id, stored in the "sessionId" key in each element
                                 of the parameters list in the collect method)
        Returns    : list; list of all oscillation_id for the specified session
    """

    def getOscillations(self, session_id):
        # TODO
        return []

    def set_helical(self, helical_on):
        self.getChannelObject("helical").setValue(1 if helical_on else 0)

    def set_helical_pos(self, helical_oscil_pos):
        self.getChannelObject('helical_pos').setValue(helical_oscil_pos)

    def get_archive_directory(self, directory):
        pt = PathTemplate()
        pt.directory = directory
        return pt.get_archive_directory()

    def setMeshScanParameters(self, mesh_steps, mesh_range):
        """
        Descript. : 
        """
        self._mesh_steps = mesh_steps
        self._mesh_range = mesh_range
class ESRFMultiCollect(AbstractMultiCollect, HardwareObject):
    def __init__(self, name, detector, tunable_bl):
        AbstractMultiCollect.__init__(self)
        HardwareObject.__init__(self, name)
        self._detector = detector
        self._tunable_bl = tunable_bl
        self._centring_status = None
        self._metadataClient = None
        self.__mesh_steps = None
        self._mesh_range = None

    @property
    def _mesh_steps(self):
        return self.__mesh_steps

    @_mesh_steps.setter
    def _mesh_steps(self, steps):
        self.__mesh_steps = steps
        self._detector._mesh_steps = steps

    def execute_command(self, command_name, *args, **kwargs):
        wait = kwargs.get("wait", True)
        cmd_obj = self.getCommandObject(command_name)
        return cmd_obj(*args, wait=wait)

    def init(self):
        self.setControlObjects(
            diffractometer=self.getObjectByRole("diffractometer"),
            sample_changer=self.getObjectByRole("sample_changer"),
            lims=self.getObjectByRole("dbserver"),
            safety_shutter=self.getObjectByRole("safety_shutter"),
            machine_current=self.getObjectByRole("machine_current"),
            cryo_stream=self.getObjectByRole("cryo_stream"),
            energy=self.getObjectByRole("energy"),
            resolution=self.getObjectByRole("resolution"),
            detector_distance=self.getObjectByRole("detector_distance"),
            transmission=self.getObjectByRole("transmission"),
            undulators=self.getObjectByRole("undulators"),
            flux=self.getObjectByRole("flux"),
            detector=self.getObjectByRole("detector"),
            beam_info=self.getObjectByRole("beam_info"),
        )

        try:
            undulators = self["undulator"]
        except IndexError:
            undulators = []

        self.setBeamlineConfiguration(
            synchrotron_name="ESRF",
            directory_prefix=self.getProperty("directory_prefix"),
            default_exposure_time=self.bl_control.detector.getProperty(
                "default_exposure_time"
            ),
            minimum_exposure_time=self.bl_control.detector.getProperty(
                "minimum_exposure_time"
            ),
            detector_fileext=self.bl_control.detector.getProperty("file_suffix"),
            detector_type=self.bl_control.detector.getProperty("type"),
            detector_manufacturer=self.bl_control.detector.getProperty("manufacturer"),
            detector_model=self.bl_control.detector.getProperty("model"),
            detector_px=self.bl_control.detector.getProperty("px"),
            detector_py=self.bl_control.detector.getProperty("py"),
            undulators=undulators,
            focusing_optic=self.getProperty("focusing_optic"),
            monochromator_type=self.getProperty("monochromator"),
            beam_divergence_vertical=self.bl_control.beam_info.getProperty(
                "beam_divergence_vertical"
            ),
            beam_divergence_horizontal=self.bl_control.beam_info.getProperty(
                "beam_divergence_horizontal"
            ),
            polarisation=self.getProperty("polarisation"),
            maximum_phi_speed=self.getProperty("maximum_phi_speed"),
            minimum_phi_oscillation=self.getProperty("minimum_phi_oscillation"),
            input_files_server=self.getProperty("input_files_server"),
        )

        self._detector.addCommand = self.addCommand
        self._detector.addChannel = self.addChannel
        self._detector.getCommandObject = self.getCommandObject
        self._detector.getChannelObject = self.getChannelObject
        self._detector.execute_command = self.execute_command
        self._detector.init(self.bl_control.detector, self)
        self._tunable_bl.bl_control = self.bl_control

        self.emit("collectConnected", (True,))
        self.emit("collectReady", (True,))

    @task
    def take_crystal_snapshots(self, number_of_snapshots):
        self.bl_control.diffractometer.takeSnapshots(number_of_snapshots, wait=True)

    @task
    def data_collection_hook(self, data_collect_parameters):
        if self._metadataClient is None:
            self._metadataClient = MXCuBEMetadataClient(self)
        self._metadataClient.start(data_collect_parameters)

    @task
    def data_collection_end_hook(self, data_collect_parameters):
        self._metadataClient.end(data_collect_parameters)

    def do_prepare_oscillation(self, start, end, exptime, npass):
        return self.execute_command("prepare_oscillation", start, end, exptime, npass)

    @task
    def oscil(self, start, end, exptime, npass, wait=False):
        if math.fabs(end - start) < 1e-4:
            self.open_fast_shutter()
            time.sleep(exptime)
            self.close_fast_shutter()
        else:
            return self.execute_command("do_oscillation", start, end, exptime, npass)

    @task
    def set_transmission(self, transmission_percent):
        self.bl_control.transmission.setTransmission(transmission_percent)

    def set_wavelength(self, wavelength):
        return self._tunable_bl.set_wavelength(wavelength)

    def set_energy(self, energy):
        return self._tunable_bl.set_energy(energy)

    @task
    def set_resolution(self, new_resolution):
        return

    @task
    def move_detector(self, detector_distance):
        return

    @task
    def data_collection_cleanup(self):
        try:
            self.stop_oscillation()
        finally:
            self.close_fast_shutter()

    @task
    def close_fast_shutter(self):
        self.execute_command("close_fast_shutter")

    @task
    def open_fast_shutter(self):
        self.execute_command("open_fast_shutter")

    @task
    def move_motors(self, motor_position_dict):
        for motor in motor_position_dict.keys():  # iteritems():
            position = motor_position_dict[motor]
            if isinstance(motor, string_types):
                # find right motor object from motor role in diffractometer obj.
                motor_role = motor
                motor = self.bl_control.diffractometer.getDeviceByRole(motor_role)
                del motor_position_dict[motor_role]
                if motor is None:
                    continue
                motor_position_dict[motor] = position

            logging.getLogger("HWR").info(
                "Moving motor '%s' to %f", motor.getMotorMnemonic(), position
            )
            motor.move(position)

        while any([motor.motorIsMoving() for motor in motor_position_dict]):
            logging.getLogger("HWR").info("Waiting for end of motors motion")
            time.sleep(0.02)

    @task
    def open_safety_shutter(self):
        self.bl_control.safety_shutter.openShutter()
        while self.bl_control.safety_shutter.getShutterState() == "closed":
            time.sleep(0.1)

    def safety_shutter_opened(self):
        return self.bl_control.safety_shutter.getShutterState() == "opened"

    @task
    def close_safety_shutter(self):
        self.bl_control.safety_shutter.closeShutter()
        while self.bl_control.safety_shutter.getShutterState() == "opened":
            time.sleep(0.1)

    @task
    def prepare_intensity_monitors(self):
        try:
            self.execute_command("adjust_gains")
        except AttributeError:
            pass

    def prepare_acquisition(
        self,
        take_dark,
        start,
        osc_range,
        exptime,
        npass,
        number_of_images,
        comment="",
        trigger_mode=None,
    ):
        energy = self._tunable_bl.getCurrentEnergy()
        return self._detector.prepare_acquisition(
            take_dark,
            start,
            osc_range,
            exptime,
            npass,
            number_of_images,
            comment,
            energy,
            trigger_mode,
        )

    def set_detector_filenames(
        self, frame_number, start, filename, jpeg_full_path, jpeg_thumbnail_full_path
    ):
        return self._detector.set_detector_filenames(
            frame_number, start, filename, jpeg_full_path, jpeg_thumbnail_full_path
        )

    def prepare_oscillation(self, start, osc_range, exptime, npass):
        return self._detector.prepare_oscillation(start, osc_range, exptime, npass)

    def do_oscillation(self, start, end, exptime, npass):
        return self._detector.do_oscillation(start, end, exptime, npass)

    def stop_oscillation(self):
        pass

    def start_acquisition(self, exptime, npass, first_frame):
        return self._detector.start_acquisition(exptime, npass, first_frame)

    def write_image(self, last_frame):
        return self._detector.write_image(last_frame)

    def last_image_saved(self):
        return self._detector.last_image_saved()

    def stop_acquisition(self):
        return self._detector.stop_acquisition()

    def reset_detector(self):
        return self._detector.reset_detector()

    def prepare_input_files(
        self, files_directory, prefix, run_number, process_directory
    ):
        i = 1

        while True:
            xds_input_file_dirname = "xds_%s_run%s_%d" % (prefix, run_number, i)
            autoprocessing_input_file_dirname = "autoprocessing_%s_run%s_%d" % (
                prefix,
                run_number,
                i,
            )
            autoprocessing_directory = os.path.join(
                process_directory, autoprocessing_input_file_dirname
            )

            if not os.path.exists(autoprocessing_directory):
                break

            i += 1

        mosflm_input_file_dirname = "mosflm_%s_run%s_%d" % (prefix, run_number, i)

        hkl2000_dirname = "hkl2000_%s_run%s_%d" % (prefix, run_number, i)

        self.raw_data_input_file_dir = os.path.join(
            files_directory, "process", xds_input_file_dirname
        )
        self.mosflm_raw_data_input_file_dir = os.path.join(
            files_directory, "process", mosflm_input_file_dirname
        )
        self.raw_hkl2000_dir = os.path.join(files_directory, "process", hkl2000_dirname)

        for dir in (
            self.raw_data_input_file_dir,
            self.mosflm_raw_data_input_file_dir,
            self.raw_hkl2000_dir,
            autoprocessing_directory,
        ):
            self.create_directories(dir)
            logging.info("Creating processing input file directory: %s", dir)
            os.chmod(dir, 0o777)

        try:
            try:
                os.symlink(files_directory, os.path.join(process_directory, "links"))
            except os.error as e:
                if e.errno != errno.EEXIST:
                    raise
        except BaseException:
            logging.exception("Could not create processing file directory")

        return autoprocessing_directory, "", ""

    @task
    def write_input_files(self, collection_id):
        # assumes self.xds_directory and self.mosflm_directory are valid
        conn = httplib.HTTPConnection(self.bl_config.input_files_server)

        # hkl input files
        input_file_dir = self.raw_hkl2000_dir
        file_prefix = "../.."
        hkl_file_path = os.path.join(input_file_dir, "def.site")

        conn.request("GET", "/def.site/%d?basedir=%s" % (collection_id, file_prefix))
        hkl_file = open(hkl_file_path, "w")
        r = conn.getresponse()

        if r.status != 200:
            logging.error("Could not create hkl input file")
        else:
            hkl_file.write(r.read())
        hkl_file.close()
        os.chmod(hkl_file_path, 0o666)

        for input_file_dir, file_prefix in (
            (self.raw_data_input_file_dir, "../.."),
            (self.xds_directory, "../links"),
        ):
            xds_input_file = os.path.join(input_file_dir, "XDS.INP")
            conn.request("GET", "/xds.inp/%d?basedir=%s" % (collection_id, file_prefix))
            xds_file = open(xds_input_file, "w")
            r = conn.getresponse()
            if r.status != 200:
                logging.error("Could not create xds input file")
            else:
                xds_file.write(r.read())
            xds_file.close()
            os.chmod(xds_input_file, 0o666)

        input_file_dir = self.mosflm_raw_data_input_file_dir
        file_prefix = "../.."
        mosflm_input_file = os.path.join(input_file_dir, "mosflm.inp")
        conn.request("GET", "/mosflm.inp/%d?basedir=%s" % (collection_id, file_prefix))
        mosflm_file = open(mosflm_input_file, "w")
        mosflm_file.write(conn.getresponse().read())
        mosflm_file.close()
        os.chmod(mosflm_input_file, 0o666)

        # also write input file for STAC
        for stac_om_input_file_name, stac_om_dir in (
            ("xds.descr", self.xds_directory),
            ("mosflm.descr", self.mosflm_raw_data_input_file_dir),
            ("xds.descr", self.raw_data_input_file_dir),
        ):
            stac_om_input_file = os.path.join(stac_om_dir, stac_om_input_file_name)
            conn.request("GET", "/stac.descr/%d" % collection_id)
            stac_om_file = open(stac_om_input_file, "w")
            stac_template = conn.getresponse().read()
            if stac_om_input_file_name.startswith("xds"):
                om_type = "xds"
                if stac_om_dir == self.raw_data_input_file_dir:
                    om_filename = os.path.join(stac_om_dir, "CORRECT.LP")
                else:
                    om_filename = os.path.join(
                        stac_om_dir, "xds_fastproc", "CORRECT.LP"
                    )
            else:
                om_type = "mosflm"
                om_filename = os.path.join(stac_om_dir, "bestfile.par")

            stac_om_file.write(
                stac_template.format(
                    omfilename=om_filename,
                    omtype=om_type,
                    phi=self.bl_control.diffractometer.phiMotor.getPosition(),
                    sampx=self.bl_control.diffractometer.sampleXMotor.getPosition(),
                    sampy=self.bl_control.diffractometer.sampleYMotor.getPosition(),
                    phiy=self.bl_control.diffractometer.phiyMotor.getPosition(),
                )
            )
            stac_om_file.close()
            os.chmod(stac_om_input_file, 0o666)

    def get_wavelength(self):
        return self._tunable_bl.get_wavelength()

    def get_detector_distance(self):
        return

    def get_resolution(self):
        return self.bl_control.resolution.getPosition()

    def get_transmission(self):
        return self.bl_control.transmission.getAttFactor()

    def get_undulators_gaps(self):
        all_gaps = {"Unknown": None}
        _gaps = {}
        try:
            _gaps = self.bl_control.undulators.getUndulatorGaps()
        except BaseException:
            logging.getLogger("HWR").exception("Could not get undulator gaps")
        all_gaps.clear()
        for key in _gaps:
            if "_Position" in key:
                nkey = key[:-9]
                all_gaps[nkey] = _gaps[key]
            else:
                all_gaps = _gaps
        return all_gaps

    def get_resolution_at_corner(self):
        return self.execute_command("get_resolution_at_corner")

    def get_beam_size(self):
        return (
            self.execute_command("get_beam_size_x"),
            self.execute_command("get_beam_size_y"),
        )

    def get_slit_gaps(self):
        return (
            self.execute_command("get_slit_gap_h"),
            self.execute_command("get_slit_gap_v"),
        )

    def get_beam_shape(self):
        return self.execute_command("get_beam_shape")

    def get_measured_intensity(self):
        try:
            val = self.getChannelObject("image_intensity").getValue()
            return float(val)
        except BaseException:
            return 0

    def get_machine_current(self):
        if self.bl_control.machine_current:
            try:
                return self.bl_control.machine_current.getCurrent()
            except BaseException:
                return -1
        else:
            return 0

    def get_machine_message(self):
        if self.bl_control.machine_current:
            return self.bl_control.machine_current.getMessage()
        else:
            return ""

    def get_machine_fill_mode(self):
        if self.bl_control.machine_current:
            return self.bl_control.machine_current.getFillMode()
        else:
            ""

    def get_cryo_temperature(self):
        while True:
            logging.info("Reading cryostream temperature")
            try:
                T = self.bl_control.cryo_stream.getTemperature()
            except Exception:
                time.sleep(0.1)
                continue
            else:
                return T

    def getCurrentEnergy(self):
        return self._tunable_bl.getCurrentEnergy()

    def get_beam_centre(self):
        return (
            self.execute_command("get_beam_centre_x"),
            self.execute_command("get_beam_centre_y"),
        )

    def getBeamlineConfiguration(self, *args):
        # TODO: change this to stop using a dictionary at the other end
        return self.bl_config._asdict()

    def isConnected(self):
        return True

    def isReady(self):
        return True

    def sampleChangerHO(self):
        return self.bl_control.sample_changer

    def diffractometer(self):
        return self.bl_control.diffractometer

    def dbServerHO(self):
        return self.bl_control.lims

    def sanityCheck(self, collect_params):
        return

    def setBrick(self, brick):
        return

    def directoryPrefix(self):
        return self.bl_config.directory_prefix

    def store_image_in_lims(self, frame, first_frame, last_frame):
        if isinstance(self._detector, CcdDetector):
            return True

        if isinstance(self._detector, PixelDetector):
            if first_frame or last_frame:
                return True

    def get_flux(self):
        return self.bl_control.flux.getCurrentFlux()

    @task
    def generate_image_jpeg(self, filename, jpeg_path, jpeg_thumbnail_path):
        directories = filename.split(os.path.sep)
        try:
            if directories[1] == "data" and directories[2] == "gz":
                if directories[3] == "visitor":
                    proposal = directories[4]
                    beamline = directories[5]
                elif directories[4] == "inhouse":
                    proposal = directories[5]
                    beamline = directories[3]
                else:
                    proposal = "unknown"
                    beamline = "unknown"

            elif directories[2] == "visitor":
                beamline = directories[4]
                proposal = directories[3]
            else:
                beamline = directories[2]
                proposal = directories[4]
        except BaseException:
            beamline = "unknown"
            proposal = "unknown"
        host, port = self.getProperty("bes_jpeg_hostport").split(":")
        conn = httplib.HTTPConnection(host, int(port))

        params = urllib.urlencode(
            {
                "image_path": filename,
                "jpeg_path": jpeg_path,
                "jpeg_thumbnail_path": jpeg_thumbnail_path,
                "initiator": beamline,
                "externalRef": proposal,
                "reuseCase": "true",
            }
        )
        conn.request(
            "POST",
            "/BES/bridge/rest/processes/CreateThumbnails/RUN?%s" % params,
            headers={"Accept": "text/plain"},
        )
        conn.getresponse()

    """
    getOscillation
        Description: Returns the parameters (and results) of an oscillation.
        Type       : method
        Arguments  : oscillation_id (int; the oscillation id, the last parameters of the collectOscillationStarted
                                     signal)
        Returns    : tuple; (blsampleid,barcode,location,parameters)
    """

    def getOscillation(self, oscillation_id):
        return self.oscillations_history[oscillation_id - 1]

    def sampleAcceptCentring(self, accepted, centring_status):
        self.sample_centring_done(accepted, centring_status)

    def setCentringStatus(self, centring_status):
        self._centring_status = centring_status

    """
    getOscillations
        Description: Returns the history of oscillations for a session
        Type       : method
        Arguments  : session_id (int; the session id, stored in the "sessionId" key in each element
                                 of the parameters list in the collect method)
        Returns    : list; list of all oscillation_id for the specified session
    """

    def getOscillations(self, session_id):
        # TODO
        return []

    def set_helical(self, helical_on):
        self.getChannelObject("helical").setValue(1 if helical_on else 0)

    def set_helical_pos(self, helical_oscil_pos):
        self.getChannelObject("helical_pos").setValue(helical_oscil_pos)

    def get_archive_directory(self, directory):
        pt = PathTemplate()
        pt.directory = directory
        return pt.get_archive_directory()

    def setMeshScanParameters(self, mesh_steps, mesh_range):
        """
        Descript. :
        """
        self._mesh_steps = mesh_steps
        self._mesh_range = mesh_range