BU before changes
This commit is contained in:
38
furka.py
38
furka.py
@ -5,11 +5,13 @@ from slic.core.acquisition import PVAcquisition
|
||||
from slic.core.adjustable import PVAdjustable, DummyAdjustable
|
||||
from slic.core.condition import PVCondition
|
||||
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.smaract import SmarActAxis
|
||||
from slic.gui import GUI
|
||||
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 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_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")
|
||||
|
||||
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 = [
|
||||
"SATFE10-PEPG046:FCUP-INTENSITY-CAL",
|
||||
"SATFE10-PEPG046-EVR0:CALCI",
|
||||
"SATFE10-PEPG046:PHOTON-ENERGY-PER-PULSE-AVG",
|
||||
"SATES30-LSCP10-FNS:CH0:VAL_GET",
|
||||
"SATES30-LSCP10-FNS:CH1:VAL_GET",
|
||||
@ -38,8 +46,10 @@ channels = [
|
||||
|
||||
pvs = [
|
||||
"SATFE10-PEPG046:PHOTON-ENERGY-PER-PULSE-AVG",
|
||||
"SATES30-RETRO:MOT_RY.RVB",
|
||||
"SATES30-RETRO:MOT_Y.RVB"
|
||||
"SATES30-RETRO:MOT_RY.RBV",
|
||||
"SATES30-RETRO:MOT_X.RBV",
|
||||
"SATES30-RETRO:MOT_Y.RBV",
|
||||
"SATES30-RETRO:MOT_Z.RBV"
|
||||
]
|
||||
|
||||
live_channels = [
|
||||
@ -58,17 +68,27 @@ pgroup = "p19197" #Commissioning p group
|
||||
check_intensity = None
|
||||
|
||||
daq = SFAcquisition(instrument, pgroup, default_channels=channels, default_pvs=pvs, rate_multiplicator=1)
|
||||
daqPV = PVAcquisition(instrument, pgroup, default_channels=live_channels)
|
||||
scan = Scanner(default_acquisitions=[daq, daqPV], condition=check_intensity)
|
||||
#daqPV = PVAcquisition(instrument, pgroup, default_channels=live_channels)
|
||||
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')
|
||||
|
||||
|
||||
|
||||
|
@ -10,11 +10,11 @@ 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
|
||||
15, 16, 17, 18
|
||||
]
|
||||
|
||||
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
213
undulator_BU.py
Normal 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
187
undulator_mal.py
Normal 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
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user