diff --git a/devices/undulator.py b/devices/undulator.py index 6a6d378..f12d430 100644 --- a/devices/undulator.py +++ b/devices/undulator.py @@ -7,6 +7,9 @@ from logzero import logger as log from slic.core.adjustable import Adjustable, PVAdjustable, PVEnumAdjustable from slic.core.scanner.scanbackend import wait_for_all #, stop_all +from slic.utils import cprint, tqdm_sleep + +from .delay_current import DelayCurrentConverter UND_NAME_FMT = "SATUN{:02}-UIND030" @@ -313,18 +316,81 @@ class CHIC(PVAdjustable): -class TwoColorChicane(PVAdjustable): +class TwoColorChicaneCurrent(PVAdjustable): - def __init__(self, name):#, t0=0): -# self.t0 = t0 -# name += " Two Color Chicane" - super().__init__("SATUN14-MBND100:I-SET", "SATUN14-MBND100:I-READ", process_time=1, name=name) + def __init__( + self, + pvname_setvalue="SATUN14-MBND100:I-SET", pvname_readback="SATUN14-MBND100:I-READ", name="Two Color Chicane as current", + accuracy=0.1, process_time=1, + hysteresis_protection=True, + **kwargs + ): + super().__init__( + pvname_setvalue, pvname_readback, name=name, + accuracy=accuracy, process_time=process_time, + **kwargs + ) + self.hysteresis_protection = hysteresis_protection -# def set_target_value(self, value, hold=False): -# super().set_target_value(value) + self.cycle_time = 250 + self.pv_cycle = PV("SATUN14-MBND100:CYCLE") + self.previous_target = None -# def get_current_value(self): -# return super().get_current_value() + + def set_target_value(self, value, **kwargs): + current = self.get_current_value() + if value < current: + cprint(f"Hysteresis Warning: target value {value} is smaller than the current value {current}", color="red") + if self.hysteresis_protection and value == self.previous_target: + cprint(f"target value {value} is identical to previous target value, will not try to change", color="cyan") + return + self.previous_target = value + super().set_target_value(value, **kwargs) + + + def cycle_magnet(self): + self.pv_cycle.put(1, wait=True) + tqdm_sleep(self.cycle_time) + # set the current to 1 and 2 consecutively, + # since the results after the first step always looks strange + self.set_target_value(1).wait() + sleep(1) + self.set_target_value(2).wait() + sleep(1) + + + +class TwoColorChicaneDelay(Adjustable): + + def __init__(self, ID="TWO-COLOR-CHICANE-DELAY", name="Two Color Chicane as delay", pvname_electron_energy="SATCB01:ENE-FILT-OP", hysteresis_protection=True, units="fs", **kwargs): + self.adj_current = TwoColorChicaneCurrent(hysteresis_protection=hysteresis_protection, internal=True) + self.pv_electron_energy = PV(pvname_electron_energy) + self.converter = DelayCurrentConverter() + super().__init__(ID, name=name, units=units, **kwargs) + + def get_current_value(self): + current = self.adj_current.get_current_value() + delay = self.calc_delay_fs(current) + return delay + + def set_target_value(self, delay): + current = self.calc_current_A(delay) + print(f"{current} A <- {delay} fs") + self.adj_current.set_target_value(current).wait() + + def is_moving(self): + return self.adj_current.is_moving() + + def cycle_magnet(self): + self.adj_current.cycle_magnet() + + def calc_current_A(self, delay_fs): + electron_energy = self.pv_electron_energy.get() + return self.converter.current_A(delay_fs, electron_energy) + + def calc_delay_fs(self, current_A): + electron_energy = self.pv_electron_energy.get() + return self.converter.delay_fs(current_A, electron_energy)