use the undulator Ks

This commit is contained in:
2022-03-01 11:48:01 +01:00
parent 17d28531d4
commit ce6c2c8098

253
adhoc.py
View File

@ -3,20 +3,25 @@ from time import sleep
from epics import PV
from slic.core.adjustable import PVAdjustable
from slic.core.adjustable import Adjustable, PVAdjustable
from slic.devices.device import Device
from slic.devices.simpledevice import SimpleDevice
from slic.devices.general.motor import Motor
from slic.devices.general.delay_stage import DelayStage
from slic.devices.general.smaract import SmarActAxis
from slic.devices.general.shutter import Shutter
from slic.devices.xoptics.dcm import CoupledDoubleCrystalMonoEnergyWithTimeCorrection
from undulator import Undulators
laser_pitch = SmarActAxis("SARES11-XICM125:ROX1")
laser_trans = SmarActAxis("SARES11-XICM125:TRX1")
laser_yaw = SmarActAxis("SARES11-XICM125:ROY1")
microscope_pitch = SmarActAxis("SARES11-XMI125:ROY1")
microscope_yaw = SmarActAxis("SARES11-XMI125:ROZ1")
laser_mod = PVAdjustable("SIN-TIMAST-TMA:Evt-23-Off-SP", process_time=1, name="Laser Mod")
CDCMEWTC = CoupledDoubleCrystalMonoEnergyWithTimeCorrection(limit_low=2450, limit_high=2520)
@ -24,6 +29,252 @@ CDCMEWTC = CoupledDoubleCrystalMonoEnergyWithTimeCorrection(limit_low=2450, limi
PSSS = Motor("SARFE10-PSSS059:MOTOR_Y3", name="PSSS XTAL y")
opo_delay = PVAdjustable("SLAAR03-LTIM-PDLY:DELAY", name="OPO Delay")
XrayShutter = Shutter("SARFE10-OPSH059")
import requests
class UndulatorEnergy(PVAdjustable):
def __init__(self, process_time=1):
self.process_time = process_time
super().__init__("SARUN:USER-DELTA", "SARUN03-UIND030:FELPHOTENE", process_time=0.2) # process_time here is only to insert the delta into the panel
# assert self.units == "keV"
print('units={}'.format(self.units))
self.units = "eV"
def set_target_value(self, value):
#value /= 1000
current = self.get_current_value()
delta = (value - current)
print(f"delta: {value} - {current} = {delta}")
delta /= 1000
task = super().set_target_value(delta)
sleep(0.1)
# task.wait() # make sure the delta is set correctly
#TODO: the following should be a task?
url_go = "http://sf-daq-mgmt.psi.ch:8090/run/Undulators/K_AR_scale"
reply = requests.get(url_go)#.json()
print('Pressing "GO" produced:', reply)
sleep(self.process_time) # wait for undulator change
return task
def get_current_value(self):
value = super().get_current_value() - 0.02037
value *= 1000
return value
def stop(self):
url_abort = "http://sf-daq-mgmt.psi.ch:8090/abort"
reply = requests.get(url_abort)#.json()
print('Pressing "Abort" produced:', reply)
class UndulatorCoupledDoubleCrystalMonoEnergy(Adjustable):
def __init__(self, ID, name=None, process_time=1):
# self.und = UndulatorEnergy(process_time=process_time)
self.und = Undulators()
pvname_setvalue = "SAROP11-ARAMIS:ENERGY_SP"
pvname_readback = "SAROP11-ARAMIS:ENERGY"
pvname_moving = "SAROP11-ODCM105:MOVING"
# This is the WRONG coupling, we need to make sure it is disabled!
pvname_ebeam_coupling = "SGE-OP2E-ARAMIS:MODE_SP"
pv_setvalue = PV(pvname_setvalue)
pv_readback = PV(pvname_readback)
pv_moving = PV(pvname_moving)
pv_ebeam_coupling = PV(pvname_ebeam_coupling)
units = pv_readback.units
super().__init__(ID, name=name, units=units)
self.pvnames = SimpleNamespace(
setvalue = pvname_setvalue,
readback = pvname_readback,
moving = pvname_moving,
ebeam_coupling = pvname_ebeam_coupling
)
self.pvs = SimpleNamespace(
setvalue = pv_setvalue,
readback = pv_readback,
moving = pv_moving,
ebeam_coupling = pv_ebeam_coupling
)
def get_current_value(self):
return self.pvs.readback.get()
def set_target_value(self, value, hold=False):
changer = lambda: self.move_and_wait(value)
return self._as_task(changer, hold=hold, stopper=self.stop)
def move_and_wait(self, value, wait_time=0.1):
self.disable_ebeam_coupling()
self.pvs.setvalue.put(value)
self.und.set_target_value(value)
sleep(3) #TODO: is this correct?
while self.is_moving():
sleep(wait_time)
def is_moving(self):
moving = self.pvs.moving.get()
return bool(moving)
# def enable_ebeam_coupling(self):
# self.pvs.ebeam_coupling.put(1)
def disable_ebeam_coupling(self):
self.pvs.ebeam_coupling.put(0)
# @property
# def ebeam_coupling(self):
# return self.pvs.ebeam_coupling.get(as_string=True)
class UndulatorCoupledDoubleCrystalMonoEnergyWithTimeCorrection(Adjustable):
def __init__(self, ID="UCDCMEWTC", name="Alvra DCM Undulator-coupled energy with time correction", limit_low=None, limit_high=None, process_time=1):
# self.und = UndulatorEnergy(process_time=process_time)
self.und = Undulators()
self.wait_time = 0.1
self.limit_low = limit_low
self.limit_high = limit_high
pvname_setvalue = "SAROP11-ARAMIS:ENERGY_SP"
pvname_readback = "SAROP11-ARAMIS:ENERGY"
pvname_moving = "SAROP11-ODCM105:MOVING"
# This is the WRONG coupling, we need to make sure it is disabled!
pvname_ebeam_coupling = "SGE-OP2E-ARAMIS:MODE_SP"
pv_setvalue = PV(pvname_setvalue)
pv_readback = PV(pvname_readback)
pv_moving = PV(pvname_moving)
pv_ebeam_coupling = PV(pvname_ebeam_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,
ebeam_coupling = pvname_ebeam_coupling
)
self.pvs = SimpleNamespace(
setvalue = pv_setvalue,
readback = pv_readback,
moving = pv_moving,
ebeam_coupling = pv_ebeam_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.disable_ebeam_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.move_and_wait(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 move_and_wait(self, value, wait_time=0.1):
self.disable_ebeam_coupling()
self.pvs.setvalue.put(value)
self.und.set_target_value(value)
sleep(3) #TODO: is this correct?
while self.is_moving():
sleep(wait_time)
def is_moving(self):
moving = self.pvs.moving.get()
return bool(moving)
# def enable_ebeam_coupling(self):
# self.pvs.ebeam_coupling.put(1)
def disable_ebeam_coupling(self):
self.pvs.ebeam_coupling.put(0)
# @property
# def ebeam_coupling(self):
# return self.pvs.ebeam_coupling.get(as_string=True)
# adjust this function!!
# be careful, CDCMEWTC has its own conversion!!!
def convert_E_to_distance(E): ### returns a value in mm!
#return 0.0061869 * E ### calibration May 2021, S k-edge, 2450 eV, corresponds to 41.2 fs/eV
#return 0.00524244 * E ### calibration Nov 2021, Rh L-edge, 3000 eV, corresponds to 35 fs/eV
return 0.0005445 * E ### calibration Mar 2022, Mn K-edge, 6500 eV, corresponds to 3.6 fs/eV
#und = UndulatorEnergy()
mono_und = UndulatorCoupledDoubleCrystalMonoEnergy("MONO_UND", name="Alvra DCM Undulator-coupled energy")
UCDCMEWTC = UndulatorCoupledDoubleCrystalMonoEnergyWithTimeCorrection(limit_low=2450, limit_high=2520)
class TXS(Device):