class Count(object): """X-ray detector tigger input high?""" # Was unable to use XPP:R31:EVR:21:EVENT1CNT. # Count was not counting up. F. Schotte, 26 Nov 2013 # Silke recommeded to use XPP:IPM:EVR:EVENT1CNT instead. count_PV = PV("XPP:IPM:EVR:EVENT1CNT") event_code_PV = PV("XPP:IPM:EVR:EVENT1CTRL.ENM") enabled_PV = PV("XPP:IPM:EVR:EVENT1CTRL.VME") name_PV = PV("XPP:IPM:EVR:EVENT1NAME") offset = 0 def setup(self): self.event_code_PV.value = 92 self.enabled_PV.value = 1 self.name_PV.value = "Sample Translation" def get_value(self): return int(self.count_PV.value) + self.offset def set_value(self, value): # "caput" does not change the count value. # Using a user-defined offset instead. self.offset = value - self.value ##self.count_PV.value = value value = property(get_value, set_value)
class Pulses(object): """Number of pulses per acquisition""" mode_PV = PV("ECS:SYS0:3:PLYMOD") # 0=Once,1=N times,2=Forever target_count_PV = PV("ECS:SYS0:3:REPCNT") run_PV = PV("ECS:SYS0:3:PLYCTL") count_PV = PV("ECS:SYS0:3:PLYCNT") # counting up to target count doc = "When read return the number of pulses remaining until the burst"\ "ends. When set trigger a burst with the given number of pulses." def get_value(self): """Number of pulses remaining until the burst ends""" # PV is counting up from zero to count_PV count = toint(self.target_count_PV.value) - toint(self.count_PV.value) return count def set_value(self, count): if count > 0: if self.mode_PV.value != 1: self.mode_PV.value = 1 # Repeat N Times if self.target_count_PV.value != count: self.target_count_PV.value = count self.run_PV.value = 1 if count == 0: self.run_PV.value = 0 value = property(get_value, set_value, doc=doc)
class Count(object): """X-ray detector tigger input high?""" # Was unable to use XPP:R31:EVR:21:EVENT3CNT. # Count was not counting up. F. Schotte, 1 Dec 2013 # Using XPP:IPM:EVR:EVENT2CNT instead. count_PV = PV("XPP:IPM:EVR:EVENT2CNT") event_code_PV = PV("XPP:IPM:EVR:EVENT2CTRL.ENM") enabled_PV = PV("XPP:IPM:EVR:EVENT2CTRL.VME") name_PV = PV("XPP:IPM:EVR:EVENT2NAME") offset = 0 def setup(self): self.event_code_PV.value = 94 self.enabled_PV.value = 1 self.name_PV.value = "X-ray area detector" def get_value(self): return toint(self.count_PV.value) + self.offset def set_value(self, value): # "caput" does not change the count value. # Using a user-defined offset instead. self.offset = value - self.value ##self.count_PV.value = value value = property(get_value, set_value)
class TriggerActive(object): status_PV = PV("ECS:SYS0:3:PLSTAT") # 0: Stopped, 1:Playing control_PV = PV("ECS:SYS0:3:PLYCTL") # 0: Stop, 1:Start def get_value(self): return self.status_PV.value != 0 def set_value(self, value): self.control_PV.value = 1 if value else 0 value = property(get_value, set_value)
class TriggerLevel(object): """X-ray detector tigger input high?""" polarity_PV = PV("XPP:R31:EVR:21:CTRL.DG1P") def get_value(self): return self.polarity_PV.value == 1 def set_value(self, value): self.polarity_PV.value = 1 if value else 0 value = property(get_value, set_value)
class XRayShutterEnabled(object): """X-ray shutter trigger enabled?""" enabled_PV = PV("XPP:R32:EVR:32:EVENT1CTRL.ENAB") def get_value(self): return self.enabled_PV.value def set_value(self, value): self.enabled_PV.value = 1 if value else 0 value = property(get_value, set_value)
class ContinuousTrigger(object): """Is continuous triggering enabled?""" mode_PV = PV("ECS:SYS0:3:PLYMOD") run_PV = PV("ECS:SYS0:3:PLYCTL") def get_value(self): """Is continuous triggering enabled?""" return self.mode_PV.value == 2 and self.run_PV.value == 1 def set_value(self, value): if bool(value) == True: if self.mode_PV.value != 2: self.mode_PV.value = 2 # Repeat Forever self.run_PV.value = 1 else: self.run_PV.value = 0 value = property(get_value, set_value) def __repr__(self): return self.PV.name
class XRayAttenuatorInserted(object): """X-ray shutter trigger enabled?""" polarity_PV = PV("XPP:R32:EVR:32:CTRL.DG2P") def get_value(self): level_OK = self.polarity_PV.value == 1 active = xray_attenuator_enabled.value and trigger_active.value return level_OK and not active def set_value(self, value): self.polarity_PV.value = 1 if value else 0 value = property(get_value, set_value)
class Laue_Crystallography(object): """Serial Laue crystallography""" from persistent_property import persistent_property from action_property import action_property # instumentation from image_scan import image_scan from cavro_centris_syringe_pump_IOC import volume, port # volume[0],...,volume[3] mother_liquor = volume[0] mother_liquor_dV = persistent_property("mother_liquor_dV", 10) crystal_liquor = volume[2] crystal_liquor_dV = persistent_property("crystal_liquor_dV", 10) from cavro_centris_syringe_pump import PumpController pump = p = PumpController() from cavro_centris_syringe_pump import S_flow, S_load, S_flowIM from CA import PV upstream_pressure = PV("NIH:DI245.56671FE403.CH1.pressure") downstream_pressure = PV("NIH:DI245.56671FE403.CH3.pressure") from instrumentation import microscope_camera as camera from instrumentation import DetZ det_inserted_pos = 185.8 det_retracted_pos = 485.8 def get_det_inserted(self): from numpy import isnan, nan value = abs(self.DetZ.value-self.det_inserted_pos) < 0.001\ if not isnan(self.DetZ.value) else nan return value def set_det_inserted(self, value): if value: self.DetZ.command_value = self.det_inserted_pos else: self.DetZ.moving = False det_inserted = property(get_det_inserted, set_det_inserted) def get_det_retracted(self): from numpy import isnan, nan value = abs(self.DetZ.value-self.det_retracted_pos) < 0.001\ if not isnan(self.DetZ.value) else nan return value def set_det_retracted(self, value): if value: self.DetZ.command_value = self.det_retracted_pos else: self.DetZ.moving = False det_retracted = property(get_det_retracted, set_det_retracted) def get_stage_enabled(self): from instrumentation import SampleX, SampleY, SampleZ return SampleX.enabled * SampleY.enabled * SampleZ.enabled def set_stage_enabled(self, value): from instrumentation import SampleX, SampleY, SampleZ SampleX.enabled, SampleY.enabled, SampleZ.enabled = True, True, True stage_enabled = property(get_stage_enabled, get_stage_enabled) @property def stage_online(self): from instrumentation import ensemble return ensemble.connected def get_centered(self): return self.image_scan.position == self.image_scan.center def set_centered(self, value): if value: self.image_scan.position = self.image_scan.center centered = property(get_centered, set_centered) def define_center(self): self.image_scan.center = self.image_scan.position inserted = centered @property def retracted_position(self): x, y, z = self.image_scan.center return x, y + 11, z def get_retracted(self): return self.image_scan.position == self.retracted_position def set_retracted(self, value): if value: self.image_scan.position = self.retracted_position retracted = property(get_retracted, set_retracted) scanning = action_property("self.image_scan.acquire()", stop="self.image_scan.cancelled = True") @property def crystal_coordinates(self): """X,Y,Z in mm as formatted text""" XYZ = self.image_scan.crystal_XYZ lines = "\n".join(["%+.3f,%+.3f,%+.3f" % tuple(xyz) for xyz in XYZ.T]) return lines @property def pump_online(self): from numpy import isnan return not isnan(self.volume[0].value) def init(self): """Home all motors""" self.p.init() def get_flowing(self): return self.mother_liquor.moving and \ self.mother_liquor.speed == self.S_flow def set_flowing(self, value): if value: self.p.flow() else: self.p.abort() flowing = property(get_flowing, set_flowing) def inject(self): """Load crystals""" self.inject_count += 1 self.p.inject() inject_count = persistent_property("inject_count", 0) def get_injecting(self): return self.mother_liquor.moving \ and self.mother_liquor.speed == self.S_flowIM def set_injecting(self, value): if value: self.inject_count += 1 self.p.inject() else: self.p.abort() injecting = property(get_injecting, set_injecting) def get_mother_liquor_refilling(self): return self.mother_liquor.moving \ and self.mother_liquor.speed == self.S_load def set_mother_liquor_refilling(self, value): if value: self.p.refill_1() else: self.p.abort() mother_liquor_refilling = property(get_mother_liquor_refilling, set_mother_liquor_refilling) def get_crystal_liquor_refilling(self): return self.crystal_liquor.moving \ and self.crystal_liquor.speed == self.S_load def set_crystal_liquor_refilling(self, value): if value: self.inject_count = 0 self.p.refill_3() else: self.p.abort() crystal_liquor_refilling = property(get_crystal_liquor_refilling, set_crystal_liquor_refilling) image_rootname = persistent_property("image_rootname", "") def save_image(self): """Record photo""" from os.path import dirname directory = dirname(self.image_scan.directory) filename = "%s/%s.jpg" % (directory, self.image_rootname) self.camera.save_image(filename)
"""This tells the number of seconds to the next top-up. This is needed to decide whether it is necessary to postpone the next image until after the next top-up, to avoid collecting data during a top-up. """ __version__ = "1.0" from CA import PV time_to_next_refill = PV("Mt:TopUpTime2Inject")
""" This is to log the tempeature of the ILX Lightwave LDT-5948 Precision Temperature Controller Friedrich Schotte, APS, 4 Dec 2009 """ from temperature_controller import temperature_controller from CA import PV from scan import timescan temperature = temperature_controller.temperature power = temperature_controller.power chillerT = PV("14Keithley1:DMM1Ch3_raw.VAL") logfile = "//id14bxf/data/anfinrud_1004/Scans/2010.04.14-01 Temperature.log" ##logfile = None timescan([temperature,power,chillerT],waiting_time=1,logfile=logfile)
class XrayAttenuator(object): motors = [motor("XPP:SB2:MMS:%d" % i) for i in range(26, 16, -1)] for motor in motors: motor.readback_slop = 0.075 thicknesses = [0.020 * 2**i for i in range(0, len(motors))] outpos = [0] * len(motors) inpos = [20] * len(motors) inpos[3] = 19 # Filter #4 is damaged at position 20 mm. photon_energy_PV = PV("SIOC:SYS0:ML00:AO627") # in eV """Variable Si X-ray attenuator of XPP hutch""" def get_transmission(self): from numpy import exp x = self.pathlength E = self.photon_energy return exp(-float(Si_mu(E)) * x) def set_transmission(self, T): from numpy import log E = self.photon_energy x = -log(T) / float(Si_mu(E)) self.pathlength = x transmission = property(get_transmission, set_transmission) value = transmission def get_photon_energy(self): "Photon energy in eV" return self.photon_energy_PV.value photon_energy = property(get_photon_energy) def get_pathlength(self): "Thickness of silicon the X-ray beam passes through" pathlength = 0 inserted = self.inserted for i in range(0, len(self.motors)): if inserted[i]: pathlength += self.thicknesses[i] return pathlength def set_pathlength(self, pathlength): from numpy import rint pathlength = min(pathlength, sum(self.thicknesses)) steps = int(rint(pathlength / min(self.thicknesses))) insert = [(steps & 2**i != 0) for i in range(0, len(self.motors))] self.inserted = insert pathlength = property(get_pathlength, set_pathlength) def get_inserted(self): "True of False for each abosrber, list of 10" positions = self.positions return [ abs(positions[i] - self.inpos[i]) < abs(positions[i] - self.outpos[i]) for i in range(0, len(self.motors)) ] def set_inserted(self, insert): "Inserted: list of booleans, one for each absorber" positions = [ self.inpos[i] if insert[i] else self.outpos[i] for i in range(0, len(self.motors)) ] self.positions = positions inserted = property(get_inserted, set_inserted) def get_positions(self): "Position for each absorber, list of 10" return [self.motors[i].value for i in range(0, len(self.motors))] def set_positions(self, positions): "Inserted: list of positions, one for each absorber" for i in range(0, len(self.motors)): self.motors[i].value = positions[i] positions = property(get_positions, set_positions) def get_moving(self): """Is any of the absorbers moving?""" return any(motor.moving for motor in self.motors) def set_moving(self, moving): """If moving = False, stop all motors.""" for motor in self.motors: motor.moving = moving moving = property(get_moving, set_moving) def stop(self): """Stop all motors.""" for motor in self.motors: motor.stop()
class EventSequencer(object): """Trigger generator""" stop_at_step = PV("ECS:SYS0:3:LEN") event_code = PV("ECS:SYS0:3:SEQ.A") delta_beam = PV("ECS:SYS0:3:SEQ.B") fiducial_delays = PV("ECS:SYS0:3:SEQ.C") burst_count = PV("ECS:SYS0:3:SEQ.D") process = PV("ECS:SYS0:3:SEQ.PROC") base_rate = PV("EVNT:SYS0:1:LCLSBEAMRATE") events = [] def clear(self): self.events = [] def add_event(self, time_mark, event_code): for i in range(len(self.events), time_mark + 1): self.events += [[]] if not event_code in self.events[time_mark]: self.events[time_mark] += [event_code] def add_burst(self, start_time_mark, end_time_mark, event_code): """start_time_mark: first end_time_mark: not included""" for i in range(start_time_mark, end_time_mark): self.add_event(i, event_code) def update(self): event_code = [] delta_beam = [] last_time_mark = 0 for i in range(0, len(self.events)): event_group = self.events[i] if len(event_group) == 0: continue event_code += event_group delta_beam += [i - last_time_mark] delta_beam += [0] * (len(event_group) - 1) last_time_mark = i assert len(event_code) == len(delta_beam) n = len(event_code) self.stop_at_step.value = n self.event_code.value = event_code + [0] * (2048 - n) self.delta_beam.value = delta_beam + [0] * (2048 - n) self.fiducial_delays.value = [0] * 2048 self.burst_count.value = [0] * 2048 # Add labels to MEDM screen event_code += [0] * (20 - len(event_code)) for i in range(0, 20): caput("XPP:ECS:IOC:01:EC_3:%02d.DESC" % i, event_code_name(event_code[i])) sleep(0.1) # needed self.process.value = 1 sleep(0.2) # needed self.process.value = 1 # needed @property def sequence_length(self): """interger value in multiples of 120-Hz cycles""" n = self.stop_at_step.value delta_beam = self.delta_beam.value sequence_length = sum(delta_beam[0:n]) return sequence_length @property def period(self): """Repetion time in seconds""" rate = tofloat(self.base_rate.value) if rate == 0: return nan period = self.sequence_length / rate return period def single_shot_setup(self): self.clear() self.add_burst(0, 1, 90) # X-ray shutter self.add_burst(2, 3, 92) # Sample translation self.add_burst(2, 3, 94) # X-ray detector self.add_burst(1, 2, 95) # Data Acquisition self.add_event(0, 96) # Timing tool reference self.add_event(13, 0) # add delay and the end for the rep rate self.update() event_receiver_setup() def collection_setup(self): self.clear() self.add_burst(1, 11, 90) # X-ray shutter self.add_burst(14, 15, 90) # X-ray shutter self.add_burst(1, 11, 91) # X-ray attenuator self.add_burst(2, 3, 92) # Sample translation self.add_burst(15, 16, 92) # Sample translation self.add_burst(14, 15, 93) # Laser shutter self.add_burst(12, 13, 94) # X-ray detector self.add_burst(25, 26, 94) # X-ray detector self.add_burst(1, 13, 95) # Data Acquisition (X-ray shutter+1) self.add_burst(25, 26, 95) # Data Acquisition (X-ray shutter+1) self.add_event(26, 0) # add delay and the end for the rep rate self.update() event_receiver_setup() def alignment_setup(self): self.clear() self.add_burst(2, 12, 90) # X-ray shutter self.add_burst(2, 12, 91) # X-ray attenuator self.add_burst(13, 14, 92) # Sample translation self.add_burst(13, 14, 94) # X-ray detector self.add_burst(3, 13, 95) # Data Acquisition (X-ray shutter+1) self.add_burst(0, 1, 95) # Data Acquisition (X-ray shutter+1) self.add_event(12, 0) # add delay and the end for the rep rate ##self.add_event(120,0) # for debugging, slow down to 1 Hz self.update() event_receiver_setup() def test_setup(self): self.clear() self.add_event(0, 90) self.add_event(0, 91) self.add_event(0, 92) self.add_event(0, 93) self.add_event(0, 94) self.add_event(24, 0) self.update()
def PV_object(self): from CA import PV return PV(self.prefix + name)
class XraySafetyShuttersEnabled(object): def __init__(self,PV_name): self.PV_name = PV_name def get_value(self): from CA import caget value = caget(self.PV_name) from numpy import nan if value is None: value = nan return value value = property(get_value) xray_safety_shutters_enabled = XraySafetyShuttersEnabled("ACIS:ShutterPermit.VAL") ID14A_shutter_auto_open = PV("14IDA:shutter_auto_enable1.VAL") ID14C_shutter_auto_open = PV("14IDA:shutter_auto_enable2.VAL") class XraySafetyShuttersAutoOpen(object): def get_value(self): return ID14A_shutter_auto_open.value and ID14C_shutter_auto_open.value def set_value(self,value): if value: ID14A_shutter_auto_open.value = True ID14C_shutter_auto_open.value = True else: ID14A_shutter_auto_open.value = False ID14C_shutter_auto_open.value = False value = property(get_value,set_value) xray_safety_shutters_auto_open = XraySafetyShuttersAutoOpen()