import logging
import math
import os
import time
from mxcubecore import HardwareRepository as HWR
from mxcubecore.BaseHardwareObjects import HardwareObject
from mxcubecore.HardwareObjects.abstract.AbstractMultiCollect import *
from mxcubecore.model.queue_model_objects import PathTemplate
from mxcubecore.utils.conversion import string_types
try:
from httplib import HTTPConnection
except Exception:
# Python3
from http.client import HTTPConnection
try:
from urllib import urlencode
except Exception:
# Python3
from urllib.parse import urlencode
[docs]class ESRFMultiCollect(AbstractMultiCollect, HardwareObject):
def __init__(self, name):
AbstractMultiCollect.__init__(self)
HardwareObject.__init__(self, name)
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
[docs] def execute_command(self, command_name, *args, **kwargs):
wait = kwargs.get("wait", True)
cmd_obj = self.get_command_object(command_name)
return cmd_obj(*args, wait=wait)
[docs] def init(self):
self._detector = HWR.beamline.detector
self.number_of_snapshots = self.get_property("num_snapshots", 4)
self.setControlObjects(
diffractometer=self.get_object_by_role("diffractometer"),
sample_changer=self.get_object_by_role("sample_changer"),
lims=self.get_object_by_role("dbserver"),
safety_shutter=self.get_object_by_role("safety_shutter"),
machine_current=self.get_object_by_role("machine_current"),
cryo_stream=self.get_object_by_role("cryo_stream"),
energy=self.get_object_by_role("energy"),
resolution=self.get_object_by_role("resolution"),
detector_distance=self.get_object_by_role("detector_distance"),
transmission=self.get_object_by_role("transmission"),
undulators=self.get_object_by_role("undulators"),
flux=self.get_object_by_role("flux"),
detector=self.get_object_by_role("detector"),
beam_info=self.get_object_by_role("beam_info"),
)
try:
undulators = self["undulator"]
except KeyError:
undulators = []
beam_div_hor, beam_div_ver = HWR.beamline.beam.get_beam_divergence()
self.setBeamlineConfiguration(
synchrotron_name="ESRF",
directory_prefix=self.get_property("directory_prefix"),
default_exposure_time=HWR.beamline.detector.get_property(
"default_exposure_time"
),
minimum_exposure_time=HWR.beamline.detector.get_property(
"minimum_exposure_time"
),
detector_fileext=HWR.beamline.detector.get_property("file_suffix"),
detector_type=HWR.beamline.detector.get_property("type"),
detector_manufacturer=HWR.beamline.detector.get_property("manufacturer"),
detector_model=HWR.beamline.detector.get_property("model"),
detector_binning_mode=HWR.beamline.detector.get_property("binning_mode"),
detector_px=HWR.beamline.detector.get_property("px"),
detector_py=HWR.beamline.detector.get_property("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"),
maximum_phi_speed=self.get_property("maximum_phi_speed"),
minimum_phi_oscillation=self.get_property("minimum_phi_oscillation"),
input_files_server=self.get_property("input_files_server"),
)
# self._detector.init(HWR.beamline.detector, self)
self.emit("collectConnected", (True,))
self.emit("collectReady", (True,))
@task
def data_collection_end_hook(self, data_collect_parameters):
self._detector._emit_status()
def prepare_oscillation(
self,
start,
osc_range,
exptime,
number_of_images,
shutterless,
first_frame,
):
if shutterless:
end = start + osc_range * number_of_images
exptime = (exptime + self._detector.get_deadtime()) * number_of_images
if first_frame:
self.do_prepare_oscillation(start, end, exptime)
else:
if osc_range < 1e-4:
# still image
end = start
else:
end = start + osc_range
self.do_prepare_oscillation(start, end, exptime)
return start, end
@task
def no_oscillation(self, exptime):
self.open_fast_shutter()
time.sleep(exptime)
self.close_fast_shutter()
@task
def do_oscillation(
self, start, end, exptime, number_of_images, shutterless, first_frame,
):
if shutterless:
if first_frame:
exptime = (exptime + self._detector.get_deadtime()) * number_of_images
self.oscillation_task = self.oscil(
start, end, exptime, number_of_images, wait=False
)
if self.oscillation_task.ready():
self.oscillation_task.get()
else:
self.oscil(start, end, exptime, number_of_images)
@task
def oscil(self, start, end, exptime, number_of_images, 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, number_of_images)
def set_wavelength(self, wavelength):
if HWR.beamline.tunable_wavelength:
return HWR.beamline.energy.set_wavelength(wavelength)
else:
return
def set_energy(self, energy):
if HWR.beamline.tunable_wavelength:
return HWR.beamline.energy.set_value(energy)
else:
return
def data_collection_cleanup(self):
try:
self.close_fast_shutter()
self.stop_oscillation()
HWR.beamline.detector.stop_acquisition()
except Exception:
logging.getLogger("HWR").exception("")
def queue_finished_cleanup(self):
logging.getLogger("user_level_log").info("Queue execution finished")
@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):
# We do not wnta to modify the input dict
motor_positions_copy = motor_position_dict.copy()
for motor in motor_positions_copy.keys(): # iteritems():
position = motor_positions_copy[motor]
if isinstance(motor, string_types):
# find right motor object from motor role in diffractometer obj.
motor_role = motor
motor = HWR.beamline.diffractometer.get_deviceby_role(motor_role)
del motor_positions_copy[motor_role]
if motor is None:
continue
motor_positions_copy[motor] = position
logging.getLogger("HWR").info(
"Moving motor '%s' to %f", motor.get_motor_mnemonic(), position
)
motor.set_value(position)
while any([motor.motorIsMoving() for motor in motor_positions_copy]):
logging.getLogger("HWR").info("Waiting for end of motors motion")
time.sleep(0.02)
def open_safety_shutter(self):
if HWR.beamline.safety_shutter.get_value().name == "CLOSED":
try:
logging.getLogger("user_level_log").info("Opening safety shutter")
HWR.beamline.safety_shutter.set_value(
HWR.beamline.safety_shutter.VALUES.OPEN, timeout=10
)
except Exception:
logging.getLogger("HWR").exception("")
def safety_shutter_opened(self):
state = False
try:
state = HWR.beamline.safety_shutter.get_value().name == "OPEN"
except Exception:
logging.getLogger("HWR").exception("")
state = True
return state
@task
def close_safety_shutter(self):
if HWR.beamline.safety_shutter.get_value().name == "OPEN":
try:
HWR.beamline.safety_shutter.set_value(
HWR.beamline.safety_shutter.VALUES.CLOSED
)
except Exception:
logging.getLogger("HWR").exception("")
@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="",
):
self._detector.prepare_acquisition(
take_dark,
start,
osc_range,
exptime,
npass,
number_of_images,
comment,
self.mesh,
self.mesh_num_lines,
)
def set_detector_filenames(
self, is_first_frame, frame_number, start, filename, shutterless
):
if is_first_frame or not shutterless:
return self._detector.set_detector_filenames(frame_number, start, filename)
def stop_oscillation(self):
HWR.beamline.diffractometer.abort_cmd()
def start_acquisition(self, exptime, npass, first_frame, shutterless):
if first_frame:
return self._detector.start_acquisition()
@task
def write_image(self, last_frame):
if last_frame:
res = self._detector.wait_ready()
self._detector._emit_status()
return res
def last_image_saved(self, total_time, exptime, num_images):
# check here if fast shutter is open ?
if HWR.beamline.detector.status["acq_satus"] == "RUNNING":
return int(total_time / exptime)
else:
return HWR.beamline.detector.last_image_saved()
def stop_acquisition(self):
return self._detector.stop_acquisition()
def reset_detector(self):
return self._detector.reset()
@task
def write_input_files(self, collection_id):
# assumes self.xds_directory and self.mosflm_directory are valid
conn = 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().decode())
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")
res = conn.getresponse()
if res.status != 200:
logging.error("Could not create xds input file")
else:
xds_file.write(res.read().decode())
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().decode())
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().decode()
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=HWR.beamline.diffractometer.phiMotor.get_value(),
sampx=HWR.beamline.diffractometer.sampleXMotor.get_value(),
sampy=HWR.beamline.diffractometer.sampleYMotor.get_value(),
phiy=HWR.beamline.diffractometer.phiyMotor.get_value(),
)
)
stac_om_file.close()
os.chmod(stac_om_input_file, 0o666)
def get_wavelength(self):
return HWR.beamline.energy.get_wavelength()
def get_undulators_gaps(self):
all_gaps = {"Unknown": None}
_gaps = {}
try:
_gaps = HWR.beamline.undulators
except Exception:
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.get_channel_object("image_intensity").getValue()
# return float(val)
# except Exception:
# return 0
def get_machine_current(self):
if HWR.beamline.machine_info:
try:
return HWR.beamline.machine_info.get_current()
except Exception:
return -1
else:
return 0
def get_machine_message(self):
if HWR.beamline.machine_info:
return HWR.beamline.machine_info.get_message()
else:
return ""
def get_machine_fill_mode(self):
if HWR.beamline.machine_info:
return HWR.beamline.machine_info.get_fill_mode()
else:
""""""
def get_cryo_temperature(self):
while True:
logging.info("Reading cryostream temperature")
try:
T = HWR.beamline.cryo_stream.getTemperature()
except Exception:
time.sleep(0.1)
continue
else:
return T
def get_current_energy(self):
return HWR.beamline.energy.get_value()
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 is_connected(self):
return True
[docs] def is_ready(self):
return True
def sampleChangerHO(self):
return HWR.beamline.sample_changer
def diffractometer(self):
return HWR.beamline.diffractometer
def dbServerHO(self):
return HWR.beamline.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 first_frame or last_frame:
return True
@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 Exception:
beamline = "unknown"
proposal = "unknown"
host, port = self.get_property("bes_jpeg_hostport").split(":")
conn = HTTPConnection(host, int(port))
params = 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.get_channel_object("helical").set_value(1 if helical_on else 0)
def set_helical_pos(self, helical_oscil_pos):
self.get_channel_object("helical_pos").set_value(helical_oscil_pos)
def get_archive_directory(self, directory):
pt = PathTemplate()
pt.directory = directory
return pt.get_archive_directory()
[docs] def setMeshScanParameters(self, mesh_steps, mesh_range):
"""
Descript. :
"""
self._mesh_steps = mesh_steps
self._mesh_range = mesh_range