BU before changes

This commit is contained in:
gac-furka
2021-12-03 15:34:41 +01:00
parent 1b7d22a8b4
commit 44290ea065
4 changed files with 431 additions and 11 deletions

View File

@ -5,11 +5,13 @@ from slic.core.acquisition import PVAcquisition
from slic.core.adjustable import PVAdjustable, DummyAdjustable from slic.core.adjustable import PVAdjustable, DummyAdjustable
from slic.core.condition import PVCondition from slic.core.condition import PVCondition
from slic.core.scanner import Scanner from slic.core.scanner import Scanner
from slic.devices.general.delay_stage import Delay from slic.devices.general.delay_stage import DelayStage
from slic.devices.general.motor import Motor from slic.devices.general.motor import Motor
from slic.devices.general.smaract import SmarActAxis from slic.devices.general.smaract import SmarActAxis
from slic.gui import GUI from slic.gui import GUI
from slic.utils import devices from slic.utils import devices
from slic.devices.simpledevice import SimpleDevice
from slic.utils import as_shortcut, Marker
from undulator import Undulators from undulator import Undulators
from undulator import Mono from undulator import Mono
@ -21,14 +23,20 @@ mot_y = Motor("SATES30-RETRO:MOT_Y", name="Retro Y")
mot_z = Motor("SATES30-RETRO:MOT_Z", name="Retro Z") mot_z = Motor("SATES30-RETRO:MOT_Z", name="Retro Z")
mot_theta = Motor("SATES30-RETRO:MOT_RY", name="Retro Theta") mot_theta = Motor("SATES30-RETRO:MOT_RY", name="Retro Theta")
retro = SimpleDevice("Retro Stages", x=mot_x, y=mot_y, z=mot_z, theta=mot_theta)
#CH0 = PVAdjustable("SATES30-LSCP10-FNS:CH0:VAL_GET") #CH0 = PVAdjustable("SATES30-LSCP10-FNS:CH0:VAL_GET")
und = Undulators(name="Undulators") und = Undulators(name="Undulators")
Mon = Mono("SATOP11-OSGM087") #Mon = Mono("SATOP11-OSGM087")
Mon = PVAdjustable("SATOP11-OSGM087:SetEnergy", pvname_done_moving="SATOP11-OSGM087:MOVING", name="MONO")
laser_delay = DelayStage("SLAAT31-LMOT-M808:MOT", name="Laser Delay")
laser_WP = Motor("SLAAT31-LMOT-M801:MOT", name="Laser WavePlate")
channels = [ channels = [
"SATFE10-PEPG046:FCUP-INTENSITY-CAL", "SATFE10-PEPG046:FCUP-INTENSITY-CAL",
"SATFE10-PEPG046-EVR0:CALCI",
"SATFE10-PEPG046:PHOTON-ENERGY-PER-PULSE-AVG", "SATFE10-PEPG046:PHOTON-ENERGY-PER-PULSE-AVG",
"SATES30-LSCP10-FNS:CH0:VAL_GET", "SATES30-LSCP10-FNS:CH0:VAL_GET",
"SATES30-LSCP10-FNS:CH1:VAL_GET", "SATES30-LSCP10-FNS:CH1:VAL_GET",
@ -38,8 +46,10 @@ channels = [
pvs = [ pvs = [
"SATFE10-PEPG046:PHOTON-ENERGY-PER-PULSE-AVG", "SATFE10-PEPG046:PHOTON-ENERGY-PER-PULSE-AVG",
"SATES30-RETRO:MOT_RY.RVB", "SATES30-RETRO:MOT_RY.RBV",
"SATES30-RETRO:MOT_Y.RVB" "SATES30-RETRO:MOT_X.RBV",
"SATES30-RETRO:MOT_Y.RBV",
"SATES30-RETRO:MOT_Z.RBV"
] ]
live_channels = [ live_channels = [
@ -58,17 +68,27 @@ pgroup = "p19197" #Commissioning p group
check_intensity = None check_intensity = None
daq = SFAcquisition(instrument, pgroup, default_channels=channels, default_pvs=pvs, rate_multiplicator=1) daq = SFAcquisition(instrument, pgroup, default_channels=channels, default_pvs=pvs, rate_multiplicator=1)
daqPV = PVAcquisition(instrument, pgroup, default_channels=live_channels) #daqPV = PVAcquisition(instrument, pgroup, default_channels=live_channels)
scan = Scanner(default_acquisitions=[daq, daqPV], condition=check_intensity) scan = Scanner(default_acquisitions=[daq], condition=check_intensity)
gui = GUI(scan) gui = GUI(scan, show_goto=True, show_spec=True, show_run=True)
scanPV = Scanner(default_acquisitions=[daqPV], condition=check_intensity) #scanPV = Scanner(default_acquisitions=[daqPV], condition=check_intensity)
'''
Button that runs a function
'''
@as_shortcut
def test():
print("test")
# use marker() to go to a marker position
'''
Single marker
'''
m1 = Marker(dummy,value=25,name='Normal IN')

View File

@ -10,11 +10,11 @@ from slic.core.scanner.scanbackend import wait_for_all #, stop_all
# 14 is the CHIC # 14 is the CHIC
n_unds = [ n_unds = [
6, 7, 8, 9, 10, 11, 12, 13, 6, 7, 8, 9, 10, 11, 12, 13,
15, 16, 17, 18, 19, 20, 21, 22 15, 16, 17, 18
] ]
und_names = [f"SATUN{n:02}-UIND030" for n in n_unds] und_names = [f"SATUN{n:02}-UIND030" for n in n_unds]
und_name_cal = "SATUN06-UIND030" und_name_cal = "SATUN13-UIND030"

213
undulator_BU.py Normal file
View File

@ -0,0 +1,213 @@
from time import sleep
import numpy as np
from epics import PV
from slic.core.adjustable import Adjustable
from slic.core.adjustable import PVAdjustable
from slic.core.scanner.scanbackend import wait_for_all #, stop_all
# 14 is the CHIC
n_unds = [
6, 7, 8, 9, 10, 11, 12, 13,
15, 16, 17, 18, 19, 20, 21, 22
]
und_names = [f"SATUN{n:02}-UIND030" for n in n_unds]
und_name_cal = "SATUN06-UIND030"
class Undulators(Adjustable):
def __init__(self, scaled=True, name="Athos Undulators", units="eV"):
super().__init__(name=name, units=units)
self.adjs = {name: Undulator(name) for name in und_names}
self.chic = CHIC(name, units)
# self.mono = Mono("SATOP11-OSGM087")
self.scaled = scaled
self.convert = ConverterEK()
a = self.adjs[und_name_cal]
self.scale = ScalerEK(a)
def set_target_value(self, value, hold=False):
k = self.convert.K(value)
if np.isnan(k):
print("K is nan for", value)
return
print(f"{k} <- {value}")
ks_current = [a.get_current_value(readback=False) for a in self.adjs.values()]
if self.scaled:
header = "scaled: "
ks_target = self.scale.K(value, ks_current)
else:
header = "all equal:"
ks_target = k * np.ones_like(ks_current)
print(header, ks_target)
print()
def change():
#TODO: replace by set_all_target_values_and_wait when print not needed anymore
tasks = []
for (name, a), k_old, k_new in zip(self.adjs.items(), ks_current, ks_target):
delta = k_old - k_new
print(f"{name}: {k_old}\t->\t{k_new}\t({delta})")
if np.isnan(k_new):
print(f"{name} skipped since target K is nan")
continue
t = a.set_target_value(k_new, hold=False)
tasks.append(t)
wait_for_all(tasks)
#print("CHIC adjustment is automatic")
#
#if abs(delta)>0.001 :
# print("E changed: waiting 10 sec for CHIC")
# sleep(10)
#else :
# sleep(2)
# print("No E change: wainting 2 sec for CHIC")
self.chic.set_target_value(value, hold=False).wait() #TODO: test whether an additional sleep is needed
print("CHIC adjustment done")
return self._as_task(change, hold=hold)
def get_current_value(self):
a = self.adjs[und_name_cal]
k = a.get_current_value()
energy = self.convert.E(k)
all_ks = [a.get_current_value() for a in self.adjs.values()]
checks = np.isclose(all_ks, k, rtol=0, atol=0.001)
# if not all(checks):
# print(f"Warning: Ks are not all close to {k}:")
# for name, k, chk in zip(self.adjs.keys(), all_ks, checks):
# if not chk:
# print(name, k)
return energy
def is_moving(self):
return any(a.is_moving() for a in self.adjs)
class Undulator(PVAdjustable):
def __init__(self, name, accuracy=0.0005):
pvname_setvalue = name + ":K_SET"
pvname_readback = name + ":K_READ"
super().__init__(pvname_setvalue, pvname_readback=pvname_readback, accuracy=accuracy, active_move=True, name=name)
self.adj_energy = PVAdjustable(name + ":FELPHOTENE")
@property
def energy(self):
return self.adj_energy.get_current_value() * 1000
class ConverterEK:
h = 4.135667696e-15 # eV * s
c = 299792458 # m / s
lambda_u = 38e-3 # m
const = 2 * h * c / lambda_u # eV
electron_rest_energy = 0.51099895 # MeV
def __init__(self, pvname_electron_energy="SATCL01-MBND100:P-READ"):
self.pv_electron_energy = PV(pvname_electron_energy)
def K(self, energy):
f = self.get_factor()
v = f / energy - 1
return np.sqrt(2 * v)
def E(self, k_value):
f = self.get_factor()
v = 1 + k_value**2 / 2
return f / v
def get_factor(self):
return self.const * self.get_gamma_squared()
def get_gamma_squared(self):
electron_energy = self.pv_electron_energy.get()
gamma = electron_energy / self.electron_rest_energy
return gamma**2
class ScalerEK:
def __init__(self, und_reference):
self.und = und_reference
def K(self, energy_target, K_current=None):
if K_current is None:
K_current = self.und.get_current_value()
K_current = np.asarray(K_current)
energy_current = self.und.energy
energy_ratio = energy_current / energy_target
K_target_squared = energy_ratio * (K_current**2 + 2) - 2
return np.sqrt(K_target_squared)
class CHIC(PVAdjustable):
def __init__(self, name, units):
name += " CHIC Energy"
super().__init__("SATUN-CHIC:PHOTON-ENERGY", name=name)
self.pvs.start = PV("SATUN-CHIC:APPLY-DELAY-OFFSET-PHASE")
self.units = units
def set_target_value(self, value, hold=False):
fudge_offset = 0
print("CHIC fudge offset is", fudge_offset)
value -= fudge_offset
value /= 1000
def change():
sleep(1)
print("CHIC setvalue")
print(value)
self.pvs.setvalue.put(value, wait=False)
sleep(1)
print("CHIC start")
self.pvs.start.put(1, wait=False)
#TODO: test whether an additional sleep is needed
sleep(1)
return self._as_task(change, hold=hold)
def get_current_value(self):
return super().get_current_value() * 1000
class Mono(PVAdjustable):
def __init__(self, name, accuracy=0.01):
pvname_setvalue = name + ":SetEnergy"
pvname_readback = name + ":photonenergy"
super().__init__(pvname_setvalue, pvname_readback=pvname_readback, accuracy=accuracy, active_move=True, name=name)

187
undulator_mal.py Normal file
View File

@ -0,0 +1,187 @@
from time import sleep
import numpy as np
from epics import PV
from slic.core.adjustable import Adjustable
from slic.core.adjustable import PVAdjustable
from slic.core.scanner.scanbackend import wait_for_all #, stop_all
# 14 is the CHIC
n_unds = [6, 7, 8, 9, 10, 11, 12, 13,
15, 16, 17, 18, 19, 20, 21, 22
]
und_names = [f"SATUN{n:02}-UIND030" for n in n_unds]
und_name_cal = "SATUN06-UIND030"
class Undulators(Adjustable):
def __init__(self, scaled=True, name="Athos Undulators", units="eV"):
super().__init__(name=name, units=units)
self.adjs = {name: Undulator(name) for name in und_names}
self.chic = CHIC(name, units)
self.scaled = scaled
self.convert = ConverterEK()
a = self.adjs[und_name_cal]
self.scale = ScalerEK(a)
def set_target_value(self, value, hold=False):
k = self.convert.K(value)
if np.isnan(k):
print("K is nan for", value)
return
print(f"{k} <- {value}")
ks_current = [a.get_current_value(readback=False) for a in self.adjs.values()]
if self.scaled:
header = "scaled: "
ks_target = self.scale.K(value, ks_current)
else:
header = "all equal:"
ks_target = k * np.ones_like(ks_current)
print(header, ks_target)
print()
def change():
#TODO: replace by set_all_target_values_and_wait when print not needed anymore
tasks = []
for (name, a), k_old, k_new in zip(self.adjs.items(), ks_current, ks_target):
delta = k_old - k_new
print(f"{name}: {k_old}\t->\t{k_new}\t({delta})")
if np.isnan(k_new):
print(f"{name} skipped since target K is nan")
continue
t = a.set_target_value(k_new, hold=False)
tasks.append(t)
wait_for_all(tasks)
print("CHIC adjustment follows")
self.chic.set_target_value(value, hold=False).wait() #TODO: test whether an additional sleep is needed
print("CHIC adjustment done")
return self._as_task(change, hold=hold)
def get_current_value(self):
a = self.adjs[und_name_cal]
k = a.get_current_value()
energy = self.convert.E(k)
all_ks = [a.get_current_value() for a in self.adjs.values()]
checks = np.isclose(all_ks, k, rtol=0, atol=0.001)
# if not all(checks):
# print(f"Warning: Ks are not all close to {k}:")
# for name, k, chk in zip(self.adjs.keys(), all_ks, checks):
# if not chk:
# print(name, k)
return energy
def is_moving(self):
return any(a.is_moving() for a in self.adjs)
class Undulator(PVAdjustable):
def __init__(self, name, accuracy=0.0005):
pvname_setvalue = name + ":K_SET"
pvname_readback = name + ":K_READ"
super().__init__(pvname_setvalue, pvname_readback=pvname_readback, accuracy=accuracy, active_move=True, name=name, internal=True)
self.adj_energy = PVAdjustable(name + ":FELPHOTENE", internal=True)
@property
def energy(self):
return self.adj_energy.get_current_value() * 1000
class ConverterEK:
h = 4.135667696e-15 # eV * s
c = 299792458 # m / s
lambda_u = 38e-3 # m
const = 2 * h * c / lambda_u # eV
electron_rest_energy = 0.51099895 # MeV
def __init__(self, pvname_electron_energy="SATCL01-MBND100:P-READ"):
self.pv_electron_energy = PV(pvname_electron_energy)
def K(self, energy):
f = self.get_factor()
v = f / energy - 1
return np.sqrt(2 * v)
def E(self, k_value):
f = self.get_factor()
v = 1 + k_value**2 / 2
return f / v
def get_factor(self):
return self.const * self.get_gamma_squared()
def get_gamma_squared(self):
electron_energy = self.pv_electron_energy.get()
gamma = electron_energy / self.electron_rest_energy
return gamma**2
class ScalerEK:
def __init__(self, und_reference):
self.und = und_reference
def K(self, energy_target, K_current=None):
if K_current is None:
K_current = self.und.get_current_value()
K_current = np.asarray(K_current)
energy_current = self.und.energy
energy_ratio = energy_current / energy_target
K_target_squared = energy_ratio * (K_current**2 + 2) - 2
return np.sqrt(K_target_squared)
class CHIC(PVAdjustable):
def __init__(self, name, units):
name += " CHIC Energy"
super().__init__("SATUN-CHIC:PHOTON-ENERGY", name=name)
self.pvs.start = PV("SATUN-CHIC:APPLY-DELAY-OFFSET-PHASE")
self.units = units
def set_target_value(self, value, hold=False):
fudge_offset = 3
print("CHIC fudge offset is", fudge_offset)
value -= fudge_offset
value /= 1000
def change():
sleep(1)
print("CHIC setvalue")
self.pvs.setvalue.put(value, wait=True)
print("CHIC start")
self.pvs.start.put(1, wait=True)
#TODO: test whether an additional sleep is needed
sleep(1)
return self._as_task(change, hold=hold)
def get_current_value(self):
return super().get_current_value() * 1000