added Pump Probe sensor; removed CCTA; adjusted undulator energy PV; adjusted reference undulator; adjusted undulator limits; adjusted conversion energy to distance

This commit is contained in:
2025-01-28 17:45:52 +01:00
parent 46c8803ce3
commit c87a8d2ba4

175
adhoc.py
View File

@ -1,8 +1,11 @@
import numpy as np
from types import SimpleNamespace from types import SimpleNamespace
from time import sleep from time import sleep
from epics import PV from epics import PV
from devices import *
from slic.core.acquisition import SFAcquisition
from slic.core.adjustable import Adjustable, PVAdjustable from slic.core.adjustable import Adjustable, PVAdjustable
from slic.core.device import Device, SimpleDevice from slic.core.device import Device, SimpleDevice
from slic.devices.general.motor import Motor from slic.devices.general.motor import Motor
@ -10,71 +13,111 @@ from slic.devices.general.delay_stage import DelayStage
from slic.devices.general.smaract import SmarActAxis from slic.devices.general.smaract import SmarActAxis
from slic.devices.general.shutter import Shutter from slic.devices.general.shutter import Shutter
from slic.devices.xoptics.dcm import CoupledDoubleCrystalMonoEnergyWithTimeCorrection from slic.devices.xoptics.dcm import CoupledDoubleCrystalMonoEnergyWithTimeCorrection
from slic.core.sensor.bsmonitor import BSMonitor
from undulator import Undulators from undulator import Undulators
ENERGY_OFFSET = -2.382769246654334 # set the mono-undulators energy offset here! ENERGY_OFFSET = -73.96501094395626 #-66.4807232884632 #-38.796532199490684 #-23.690679364204698 #-67.41724724743653 #-43.50130133659968 #-8.549246528231379 #-12.61393032963997 # -6.627670970333838 #-58.996124615499866 #set the mono-undulators energy offset here!
#s_diode_light = BSSensor("Diode", "SARES11-LSCP10-FNS:CH1:VAL_GET")
#s_i0 = BSSensor("I0", "SAROP11-PBPS122:INTENSITY")
#s_diode_dark = BSSensor("Diode", "SARES11-LSCP10-FNS:CH1:VAL_GET")
#s_i0 = BSSensor("I0", "SAROP11-PBPS122:INTENSITY")
#s = Norm("PP", s_diode, s_i0)
#s_bs = BSNorm("PP", "SARES11-LSCP10-FNS:CH1:VAL_GET", "SAROP11-PBPS122:INTENSITY")
class PP(BSMonitor):
def __init__(self,
ID = "PP",
evtmap = "SAR-CVME-TIFALL4:EvtSet",
diode = "SARES11-LSCP10-FNS:CH1:VAL_GET",
i0 = "SAROP11-PBPS122:INTENSITY",
**kwargs
):
self.cn_evtmap = evtmap
self.cn_diode = diode
self.cn_i0 = i0
chs = (self.cn_evtmap, self.cn_diode, self.cn_i0)
super().__init__(ID, chs, **kwargs)
self.cache_light = []
self.cache_dark = []
def get_aggregate(self):
return np.mean(self.cache_light) - np.mean(self.cache_dark)
def _unpack(self, data):
evtmap = data[self.cn_evtmap]
diode = data[self.cn_diode]
i0 = data[self.cn_i0]
value = diode / i0
cond_light = cond_check(evtmap)
if cond_light:
light = self.cache_light[-1]
dark = value
else:
dark = self.cache_dark[-1]
light = value
return light - dark
def _collect(self, data):
if data is None:
return
evtmap = data[self.cn_evtmap]
diode = data[self.cn_diode]
i0 = data[self.cn_i0]
value = diode / i0
cond_light = cond_check(evtmap)
if cond_light:
self.cache_light.append(value)
else:
self.cache_dark.append(value)
def cond_check(self, evtmap):
fel = evtmap[13]
laser = evtmap[18]
darkshot = evtmap[21]
return np.logical_and.reduce((fel, laser, np.logical_not(darkshot)))
def _clear(self):
self.cache_light.clear()
self.cache_dark.clear()
#pp = PP()
laser_pitch = SmarActAxis("SARES11-XICM125:ROX1") laser_pitch = SmarActAxis("SARES11-XICM125:ROX1")
laser_trans = SmarActAxis("SARES11-XICM125:TRX1") laser_trans = SmarActAxis("SARES11-XICM125:TRX1")
laser_yaw = SmarActAxis("SARES11-XICM125:ROY1") laser_yaw = SmarActAxis("SARES11-XICM125:ROY1")
microscope_pitch = SmarActAxis("SARES11-XMI125:ROY1") microscope_pitch = SmarActAxis("SARES11-XMI125:ROY1")
microscope_yaw = SmarActAxis("SARES11-XMI125:ROZ1") microscope_yaw = SmarActAxis("SARES11-XMI125:ROZ1")
laser_mod = PVAdjustable("SIN-TIMAST-TMA:Evt-23-Off-SP", process_time=1, name="Laser Mod") #laser_mod = PVAdjustable("SIN-TIMAST-TMA:Evt-23-Off-SP", process_time=1, name="Laser Mod")
CDCMEWTC = CoupledDoubleCrystalMonoEnergyWithTimeCorrection(limit_low=2450, limit_high=2520) CDCMEWTC = CoupledDoubleCrystalMonoEnergyWithTimeCorrection(limit_low=2450, limit_high=2520)
PSSS = Motor("SARFE10-PSSS059:MOTOR_Y3", name="PSSS XTAL y") PSSS = Motor("SARFE10-PSSS059:MOTOR_Y3", name="PSSS XTAL y")
opo_delay = PVAdjustable("SLAAR03-LTIM-PDLY:DELAY", name="OPO Delay") #opo_delay = PVAdjustable("SLAAR03-LTIM-PDLY:DELAY", name="OPO Delay")
XrayShutter = Shutter("SARFE10-OPSH059") XrayShutter = Shutter("SARFE10-OPSH059")
class CCTA:
def __init__(self, ID):
self.ID = ID
self.pv_mode = PV(ID + ":REPETITION-SP")
self.pv_nreps = PV(ID + ":NR-REPETITIONS-SP")
self.pv_go = PV(ID + ":CTA-START-SEQ")
self.pv_pid = PV(ID + ":seq0Ctrl-StartedAt-O")
def burst(n=1):
self.set_nreps(n)
self.set_mode_burst()
self.go()
def set_nreps(self, n):
self.pv_nreps.put(n)
def set_mode_continuous(self):
self.pv_mode.put(0)
def set_mode_burst(self):
self.pv_mode.put(1)
def go(self):
self.pv_go.put(1)
@property
def pid(self):
pid = self.pv_pid.get()
if pid is not None:
pid = int(pid)
return pid
def __repr__(self):
tn = type(self).__name__
return f"{tn} \"{self.ID}\" started at pulse ID {self.pid}"
ccta = CCTA("SAR-CCTA-ESA")
import requests import requests
class UndulatorEnergy(PVAdjustable): class UndulatorEnergy(PVAdjustable):
@ -82,7 +125,7 @@ class UndulatorEnergy(PVAdjustable):
def __init__(self, process_time=1): def __init__(self, process_time=1):
self.process_time = process_time 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 super().__init__("SARUN:USER-DELTA", "SARUN07-UIND030:FELPHOTENE", process_time=0.2) # process_time here is only to insert the delta into the panel
# assert self.units == "keV" # assert self.units == "keV"
print('units={}'.format(self.units)) print('units={}'.format(self.units))
self.units = "eV" self.units = "eV"
@ -121,7 +164,7 @@ class UndulatorCoupledDoubleCrystalMonoEnergy(Adjustable):
def __init__(self, ID, name=None, process_time=1): def __init__(self, ID, name=None, process_time=1):
# self.und = UndulatorEnergy(process_time=process_time) # self.und = UndulatorEnergy(process_time=process_time)
self.und = Undulators(energy_offset=ENERGY_OFFSET) self.und = Undulators(energy_offset=ENERGY_OFFSET, n_und_ref=7)
pvname_setvalue = "SAROP11-ARAMIS:ENERGY_SP" pvname_setvalue = "SAROP11-ARAMIS:ENERGY_SP"
pvname_readback = "SAROP11-ARAMIS:ENERGY" pvname_readback = "SAROP11-ARAMIS:ENERGY"
@ -189,15 +232,13 @@ class UndulatorCoupledDoubleCrystalMonoEnergy(Adjustable):
class UndulatorCoupledDoubleCrystalMonoEnergyWithTimeCorrection(Adjustable): 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): def __init__(self, ID="UCDCMEWTC", name="Alvra DCM Undulator-coupled energy with time correction", limit_low=2800, limit_high=3050, process_time=1):
# self.und = UndulatorEnergy(process_time=process_time) # self.und = UndulatorEnergy(process_time=process_time)
self.und = Undulators(energy_offset=ENERGY_OFFSET) # self.und = Undulators(energy_offset=ENERGY_OFFSET)
self.und = Undulators(energy_offset=ENERGY_OFFSET, n_und_ref=7)
self.wait_time = 0.1 self.wait_time = 0.1
self.limit_low = limit_low
self.limit_high = limit_high
pvname_setvalue = "SAROP11-ARAMIS:ENERGY_SP" pvname_setvalue = "SAROP11-ARAMIS:ENERGY_SP"
pvname_readback = "SAROP11-ARAMIS:ENERGY" pvname_readback = "SAROP11-ARAMIS:ENERGY"
pvname_moving = "SAROP11-ODCM105:MOVING" pvname_moving = "SAROP11-ODCM105:MOVING"
@ -217,6 +258,9 @@ class UndulatorCoupledDoubleCrystalMonoEnergyWithTimeCorrection(Adjustable):
units = pv_readback.units units = pv_readback.units
super().__init__(ID, name=name, units=units) super().__init__(ID, name=name, units=units)
self.limit_low = limit_low
self.limit_high = limit_high
self.pvnames = SimpleNamespace( self.pvnames = SimpleNamespace(
setvalue = pvname_setvalue, setvalue = pvname_setvalue,
readback = pvname_readback, readback = pvname_readback,
@ -255,11 +299,13 @@ class UndulatorCoupledDoubleCrystalMonoEnergyWithTimeCorrection(Adjustable):
current_energy = self.get_current_value() current_energy = self.get_current_value()
delta_energy = value - current_energy delta_energy = value - current_energy
#delta_energy = value
timing = self.timing timing = self.timing
current_delay = timing.get_current_value() current_delay = timing.get_current_value()
delta_delay = convert_E_to_distance(delta_energy) delta_delay = convert_E_to_distance(delta_energy)
target_delay = current_delay + delta_delay target_delay = current_delay + delta_delay
#target_delay = delta_delay
print(f"Energy = {current_energy} -> delta = {delta_energy} -> {value}") print(f"Energy = {current_energy} -> delta = {delta_energy} -> {value}")
print(f"Delay = {current_delay} -> delta = {delta_delay} -> {target_delay}") print(f"Delay = {current_delay} -> delta = {delta_delay} -> {target_delay}")
@ -308,17 +354,28 @@ class UndulatorCoupledDoubleCrystalMonoEnergyWithTimeCorrection(Adjustable):
# adjust this function!! # adjust this function!!
# be careful, CDCMEWTC has its own conversion!!! # be careful, CDCMEWTC has its own conversion!!!
def convert_E_to_distance(E): ### returns a value in mm! 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 --> this is InSb111 in the DCM! #return 0.0061869 * E ### calibration May 2021, S k-edge, 2450 eV, corresponds to 41.2 fs/eV --> this is with InSb111!!
#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 #return 0.00524244 * E ### calibration Nov 2021, Rh L-edge, 3000 eV, corresponds to 35 fs/eV at 20 mm gap
#return 0.0004692 * E ### calibration Mar 2022, Fe K-edge, 7100 eV, corresponds to 3.13 fs/eV #return 0.0005445 * E ### calibration Mar 2022, Mn K-edge, 6500 eV, corresponds to 3.6 fs/eV at 20 mm gap
return 0.0148402 * E ### calibration May 2022, S K-edge, 2470 eV, corresponds to 99 fs/eV #return 0.00029134 * E ### calibration Nov 2023, Mn K-edge, 6500 eV, corresponds to 1.9 fs/eV at 10 mm gap
#return 0.0004692 * E ### calibration Mar 2022, Fe K-edge, 7100 eV, corresponds to 3.13 fs/eV at 20 mm gap
#return 0.0148402 * E ### calibration May 2022, S K-edge, 2470 eV, corresponds to 99 fs/eV at 20 mm gap
return 0.00021 * E ### calibration Oct 2023, Ni K-edge, 8350 eV, corresponds to 1.4 fs/eV at 10 mm gap
#return 0.0067003 * E ### calibration Jan 2023, Cl K-edge / Ru L3-edge, 2830 eV, corresponds to 45 fs/eV at 20 mm gap
#return 0.00495847 * E ### calibration Jan 2023, Rh L-edge, 3000 eV, corresponds to 33 fs/eV, very similar to Nov '21
#return 0.0147342 * E ### calibration Oct 2024, S K-edge, 2470 eV, corresponds to 98 fs/eV at 20 mm gap
#params = [-3.62574226e-04, 1.62862011e+00, -1.80030011e+03] ### calibration May 2024, P K-edge, 2150 eV, corresponds to ~500 fs/eV
#p = np.poly1d(params)
#return p(E)
#und = UndulatorEnergy() #und = UndulatorEnergy()
mono_und = UndulatorCoupledDoubleCrystalMonoEnergy("MONO_UND", name="Alvra DCM Undulator-coupled energy") mono_und = UndulatorCoupledDoubleCrystalMonoEnergy("MONO_UND", name="Alvra DCM Undulator-coupled energy")
UCDCMEWTC = UndulatorCoupledDoubleCrystalMonoEnergyWithTimeCorrection(limit_low=2450, limit_high=2520) UCDCMEWTC = UndulatorCoupledDoubleCrystalMonoEnergyWithTimeCorrection(limit_low=2450, limit_high=2550)