class AttenuatorAramis: def __init__(self, ID, E_min=1500, sleeptime=1, name=None, limits=[-52, 2], pulse_picker=None): self.ID = ID self._pv_status_str = PV(ID + ":MOT2TRANS.VALD") self._pv_status_int = PV(ID + ":IDX_RB") self.E_min = E_min self._sleeptime = sleeptime self.name = name self.alias = Alias(name) self.pulse_picker = pulse_picker self.motors = [Motor(f"{self.ID}:MOTOR_{n+1}", name=f"motor{n+1}") for n in range(6)] for n, mot in enumerate(self.motors): self.__dict__[f"motor_{n+1}"] = mot self.alias.append(mot.alias) if limits: mot.set_epics_limits(*limits) def updateE(self, energy=None): while not energy: energy = PV("SARUN03-UIND030:FELPHOTENE").value energy = energy * 1000 if energy < self.E_min: energy = None print(f"Machine photon energy is below {self.E_min} - waiting for the machine to recover") sleep(self._sleeptime) PV(self.ID + ":ENERGY").put(energy) print("Set energy to %s eV" % energy) def set_transmission(self, value, energy=None): self.updateE(energy) PV(self.ID + ":3RD_HARM_SP").put(0) PV(self.ID + ":TRANS_SP").put(value) def set_transmission_third_harmonic(self, value, energy=None): self.updateE(energy) PV(self.ID + ":3RD_HARM_SP").put(1) PV(self.ID + ":TRANS_SP").put(value) def setE(self): pass def get_transmission(self, verbose=True): tFun = PV(self.ID + ":TRANS_RB").value tTHG = PV(self.ID + ":TRANS3EDHARM_RB").value if verbose: print("Transmission Fundamental: %s THG: %s" % (tFun, tTHG)) return tFun, tTHG def get_current_value(self, *args, **kwargs): return self.get_transmission(*args, verbose=False, **kwargs)[0] def set_target_value(self, value, sleeptime=10, hold=False): def changer(): self.set_transmission(value) sleep(sleeptime) if self.pulse_picker: self.pulse_picker.open() return Task(changer, hold=hold) def get_status(self): s_str = self._pv_status_str.get(as_string=True) s_int = self._pv_status_int.get() return s_str, s_int def __repr__(self): t = self.get_transmission() s = "1st harm. transmission = %g\n" % t[0] s += "3rd harm. transmission = %g\n" % t[1] s += "Targets in beam:\n" s += "%s" % self.get_status()[0] return s def __call__(self, *args, **kwargs): self.set_transmission(*args, **kwargs)
def __init__(self, ID, z_undulator=None, description=None): self.ID = ID self.targetY = Motor(ID + ":MOTOR_PROBE") self.cam = CameraCA(ID) self._led = PV(self.ID + ":LED") self.target = EnumWrapper(self.ID + ":PROBE_SP")
def __init__(self, ID, name=None): self.ID = ID self._pv = PV(ID) self.name = name self.alias = Alias(self.name, channel=self.ID, channeltype="CA")
class PvDataStream: def __init__(self, ID, name=None): self.ID = ID self._pv = PV(ID) self.name = name self.alias = Alias(self.name, channel=self.ID, channeltype="CA") def collect(self, seconds=None, samples=None): if (not seconds) and (not samples): raise Exception( "Either a time interval or number of samples need to be defined." ) try: self._pv.callbacks.pop(self._collection["ix_cb"]) except: pass self._collection = {"done": False} self.data_collected = [] if seconds: self._collection["start_time"] = time() self._collection["seconds"] = seconds stopcond = lambda: (time() - self._collection["start_time"] ) > self._collection["seconds"] def addData(**kw): if not stopcond(): self.data_collected.append(kw["value"]) else: self._pv.callbacks.pop(self._collection["ix_cb"]) self._collection["done"] = True elif samples: self._collection["samples"] = samples stopcond = lambda: len(self.data_collected) >= self._collection[ "samples"] def addData(**kw): self.data_collected.append(kw["value"]) if stopcond(): self._pv.callbacks.pop(self._collection["ix_cb"]) self._collection["done"] = True self._collection["ix_cb"] = self._pv.add_callback(addData) while not self._collection["done"]: sleep(0.005) return self.data_collected def acquire(self, hold=False, **kwargs): _acquire = lambda: self.collect(**kwargs) return Task(_acquire, hold=hold) def accumulate(self, n_buffer): if not hasattr(self, "_accumulate"): self._accumulate = {"n_buffer": n_buffer, "ix": 0, "n_cb": -1} else: self._accumulate["n_buffer"] = n_buffer self._accumulate["ix"] = 0 self._pv.callbacks.pop(self._accumulate["n_cb"], None) self._data = np.squeeze(np.zeros([n_buffer * 2, self._pv.count ])) * np.nan def addData(**kw): self._accumulate["ix"] = (self._accumulate["ix"] + 1) % self._accumulate["n_buffer"] self._data[self._accumulate["ix"]::self. _accumulate["n_buffer"]] = kw["value"] self._accumulate["n_cb"] = self._pv.add_callback(addData) def get_data(self): return self._data[self._accumulate["ix"] + 1:self._accumulate["ix"] + 1 + self._accumulate["n_buffer"]] data = property(get_data)
class CoupledDoubleCrystalMonoEnergyWithTimeCorrection(Adjustable): def __init__(self, ID="CDCMEWTC", name="Alvra DCM coupled to FEL energy with time correction", limit_low=None, limit_high=None): self.wait_time = 0.1 self.limit_low = limit_low self.limit_high = limit_high pvname_setvalue = "SAROP11-ARAMIS:ENERGY_SP" #_USER" #TODO: where did the _USER go? pvname_readback = "SAROP11-ARAMIS:ENERGY" # pvname_moving = "SGE-OP2E-ARAMIS:MOVING" pvname_moving = "SAROP11-ODCM105:MOVING" pvname_coupling = "SGE-OP2E-ARAMIS:MODE_SP" pv_setvalue = PV(pvname_setvalue) pv_readback = PV(pvname_readback) pv_moving = PV(pvname_moving) pv_coupling = PV(pvname_coupling) self.timing = Motor("SLAAR11-LMOT-M452:MOTOR_1") self.electron_energy_rb = PV("SARCL02-MBND100:P-READ") self.electron_energy_sv = PV("SGE-OP2E-ARAMIS:E_ENERGY_SP") units = pv_readback.units super().__init__(ID, name=name, units=units) self.pvnames = SimpleNamespace(setvalue=pvname_setvalue, readback=pvname_readback, moving=pvname_moving, coupling=pvname_coupling) self.pvs = SimpleNamespace(setvalue=pv_setvalue, readback=pv_readback, moving=pv_moving, coupling=pv_coupling) def get_current_value(self): return self.pvs.readback.get() def set_target_value(self, value, hold=False): ll = self.limit_low if ll is not None: if value < ll: msg = f"requested value is outside the allowed range: {value} < {ll}" print(msg) raise KeyboardInterrupt(msg) lh = self.limit_high if lh is not None: if value > lh: msg = f"requested value is outside the allowed range: {value} > {lh}" print(msg) raise KeyboardInterrupt(msg) wait_time = self.wait_time self.enable_coupling() current_energy = self.get_current_value() delta_energy = value - current_energy timing = self.timing current_delay = timing.get_current_value() delta_delay = convert_E_to_distance(delta_energy) target_delay = current_delay + delta_delay print( f"Energy = {current_energy} -> delta = {delta_energy} -> {value}") print( f"Delay = {current_delay} -> delta = {delta_delay} -> {target_delay}" ) timing.set_target_value(target_delay).wait() self.pvs.setvalue.put(value) sleep(3) # wait so that the set value has changed print("start waiting for DCM") while self.is_moving(): #TODO: moving PV seems broken sleep(wait_time) print("start waiting for electron beam") while abs(self.electron_energy_rb.get() - self.electron_energy_sv.get()) > 0.25: sleep(wait_time) sleep(wait_time) def is_moving(self): moving = self.pvs.moving.get() return bool(moving) def enable_coupling(self): self.pvs.coupling.put(1) def disable_coupling(self): self.pvs.coupling.put(0) @property def coupling(self): return self.pvs.coupling.get(as_string=True)
class AttenuatorAramis(Adjustable): def __init__(self, ID, z_undulator=None, description=None, name="Attenuator Aramis"): self.sleeptime = 5 super().__init__(ID, name=name, units=None) self._pv_status_str = PV(ID + ":MOT2TRANS.VALD") self._pv_status_int = PV(ID + ":IDX_RB") def updateE(self, energy=None): if energy == None: energy = PV("SARUN03-UIND030:FELPHOTENE").value energy = energy * 1000 PV(self.ID + ":ENERGY").put(energy) print("Set energy to %s eV" % energy) def set_transmission(self, value, energy=None): self.updateE(energy) PV(self.ID + ":3RD_HARM_SP").put(0) PV(self.ID + ":TRANS_SP").put(value) def set_transmission_third_harmonic(self, value, energy=None): self.updateE(energy) PV(self.ID + ":3RD_HARM_SP").put(1) PV(self.ID + ":TRANS_SP").put(value) def get_transmission(self, verbose=True): tFun = PV(self.ID + ":TRANS_RB").value tTHG = PV(self.ID + ":TRANS3EDHARM_RB").value if verbose: print("Transmission Fundamental: %s THG: %s" % (tFun, tTHG)) return tFun, tTHG def get_current_value(self, *args, **kwargs): return self.get_transmission(*args, verbose=False, **kwargs)[0] def set_target_value(self, value): self.set_transmission(value) sleep(self.sleeptime) def get_status(self): s_str = self._pv_status_str.get(as_string=True) s_int = self._pv_status_int.get() return s_str, s_int def __repr__(self): t = self.get_transmission(verbose=False) s = "1st harm. transmission\t= %g\n" % t[0] s += "3rd harm. transmission\t= %g\n" % t[1] s += "Targets in beam:\n" s += "%s" % self.get_status()[0] return s def __call__(self, *args, **kwargs): self.set_transmission(*args, **kwargs) def is_moving(self): raise NotImplementedError