From c87a8d2ba414b218e67313652080d60242a6302b Mon Sep 17 00:00:00 2001 From: Sven Augustin Date: Tue, 28 Jan 2025 17:45:52 +0100 Subject: [PATCH] added Pump Probe sensor; removed CCTA; adjusted undulator energy PV; adjusted reference undulator; adjusted undulator limits; adjusted conversion energy to distance --- adhoc.py | 175 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 116 insertions(+), 59 deletions(-) diff --git a/adhoc.py b/adhoc.py index 8d07882..699b91d 100644 --- a/adhoc.py +++ b/adhoc.py @@ -1,8 +1,11 @@ +import numpy as np from types import SimpleNamespace from time import sleep from epics import PV +from devices import * +from slic.core.acquisition import SFAcquisition from slic.core.adjustable import Adjustable, PVAdjustable from slic.core.device import Device, SimpleDevice 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.shutter import Shutter from slic.devices.xoptics.dcm import CoupledDoubleCrystalMonoEnergyWithTimeCorrection +from slic.core.sensor.bsmonitor import BSMonitor 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_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") +#laser_mod = PVAdjustable("SIN-TIMAST-TMA:Evt-23-Off-SP", process_time=1, name="Laser Mod") CDCMEWTC = CoupledDoubleCrystalMonoEnergyWithTimeCorrection(limit_low=2450, limit_high=2520) 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") - -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 class UndulatorEnergy(PVAdjustable): @@ -82,7 +125,7 @@ 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 + 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" print('units={}'.format(self.units)) self.units = "eV" @@ -121,7 +164,7 @@ class UndulatorCoupledDoubleCrystalMonoEnergy(Adjustable): def __init__(self, ID, name=None, process_time=1): # 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_readback = "SAROP11-ARAMIS:ENERGY" @@ -189,15 +232,13 @@ class UndulatorCoupledDoubleCrystalMonoEnergy(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 = 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.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" @@ -217,6 +258,9 @@ class UndulatorCoupledDoubleCrystalMonoEnergyWithTimeCorrection(Adjustable): units = pv_readback.units super().__init__(ID, name=name, units=units) + self.limit_low = limit_low + self.limit_high = limit_high + self.pvnames = SimpleNamespace( setvalue = pvname_setvalue, readback = pvname_readback, @@ -255,11 +299,13 @@ class UndulatorCoupledDoubleCrystalMonoEnergyWithTimeCorrection(Adjustable): current_energy = self.get_current_value() delta_energy = value - current_energy + #delta_energy = value timing = self.timing current_delay = timing.get_current_value() delta_delay = convert_E_to_distance(delta_energy) target_delay = current_delay + delta_delay + #target_delay = delta_delay print(f"Energy = {current_energy} -> delta = {delta_energy} -> {value}") print(f"Delay = {current_delay} -> delta = {delta_delay} -> {target_delay}") @@ -308,17 +354,28 @@ class UndulatorCoupledDoubleCrystalMonoEnergyWithTimeCorrection(Adjustable): # 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 --> this is InSb111 in the DCM! - #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.0004692 * E ### calibration Mar 2022, Fe K-edge, 7100 eV, corresponds to 3.13 fs/eV - return 0.0148402 * E ### calibration May 2022, S K-edge, 2470 eV, corresponds to 99 fs/eV + #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 at 20 mm gap + #return 0.0005445 * E ### calibration Mar 2022, Mn K-edge, 6500 eV, corresponds to 3.6 fs/eV at 20 mm gap + #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() 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)