Adding mono + commit after the sticky bit.

This commit is contained in:
2025-03-27 09:42:30 +01:00
parent 792e562d48
commit 3d20248efe
62 changed files with 2156 additions and 249 deletions

0
README.md Normal file → Executable file
View File

0
acquisition/SF_jupyter_acquisition.ipynb Normal file → Executable file
View File

0
acquisition/base.py Normal file → Executable file
View File

0
acquisition/multiple_daqs.py Normal file → Executable file
View File

105
beamline/Cristallina_mono.py Executable file
View File

@ -0,0 +1,105 @@
from types import SimpleNamespace
from time import sleep
import numpy as np
from slic.core.adjustable import Adjustable, PVAdjustable, PVEnumAdjustable
from slic.core.adjustable.pvchangemon import PVChangeMonitor
from slic.core.device import Device
from slic.utils.hastyepics import get_pv as PV
from slic.devices.general.motor import Motor
from slic.devices.cameras import CameraCA
class CristallinaMono(Device):
"""Cristallina mono SAROP31-ODCC110"""
def __init__(self, ID, name="Cristallina double-channel-cut monochromator", **kwargs):
super().__init__(ID, name=name, **kwargs)
self.TX = Motor(ID + ":MOT_TX1")
self.bragg1 = Motor(ID + ":MOT_RX1")
self.bragg2 = Motor(ID + ":MOT_RX2")
self.energy = Motor(ID + ":MOT_ENY")
self.energy_offset = Motor(ID + ":MOT_OFS")
self.screen = CristallinaMonoScreen("SAROP31-PSCR110", name='SAROP31-PSCR110')
class CristallinaMonoScreen(Device):
def __init__(self, ID, name="Profile Monitor", **kwargs):
super().__init__(ID, name=name, **kwargs)
self.cam = CameraCA(ID)
self.target = PVEnumAdjustable(ID + ":SCR_SP", name="target")
self.target_pos = Motor(ID + ":MOT_TY1", name="target position")
self.target_in_position = PVEnumAdjustable(ID + ":IN_POS",name="target in valid position")
def move_mono(self):
return self.target.set_target_value(1)
def move_pink(self):
return self.target.set_target_value(2)
def move_out(self):
return self.target.set_target_value(0)
# class DoubleCrystalMonoEnergy(Adjustable):
# def __init__(self, ID, name=None):
# self.wait_time = 0.1
# pvname_setvalue = "SAROP21-ARAMIS:ENERGY_SP"
# pvname_readback = "SAROP21-ARAMIS:ENERGY"
# pvname_moving = "SAROP21-ODCM098:MOVING"
# pvname_stop = "SAROP21-ODCM098:STOP.PROC"
# pv_setvalue = PV(pvname_setvalue)
# pv_readback = PV(pvname_readback)
# pv_moving = PV(pvname_moving)
# pv_stop = PV(pvname_stop)
# units = pv_readback.units
# super().__init__(ID, name=name, units=units)
# self.pvnames = SimpleNamespace(
# setvalue = pvname_setvalue,
# readback = pvname_readback,
# moving = pvname_moving,
# stop = pvname_stop
# )
# self.pvs = SimpleNamespace(
# setvalue = pv_setvalue,
# readback = pv_readback,
# moving = pv_moving,
# stop = pv_stop
# )
# def get_current_value(self):
# return self.pvs.readback.get()
# def set_current_value(self, value):
# self.pvs.setvalue.put(value)
# sleep(3)
# def set_target_value(self, value):
# self.set_current_value(value)
# # while abs(self.wait_for_valid_value() - value) > accuracy:
# while self.is_moving():
# sleep(self.wait_time)
# def wait_for_valid_value(self):
# val = np.nan
# while not np.isfinite(val):
# val = self.get_current_value()
# return val
# def is_moving(self):
# moving = self.pvs.moving.get()
# return bool(moving)
# def stop(self):
# self.pvs.stop.put(1)

0
beamline/PSSS_motion.py Normal file → Executable file
View File

0
beamline/alignment_laser.py Normal file → Executable file
View File

0
beamline/apertures.py Normal file → Executable file
View File

0
beamline/attenuator_scans.py Normal file → Executable file
View File

0
beamline/bernina_mono.py Normal file → Executable file
View File

12
beamline/components.py Normal file → Executable file
View File

@ -3,10 +3,11 @@ from loguru import logger
from slic.devices.xoptics.aramis_attenuator import Attenuator
from slic.devices.xoptics.pulsepicker import PulsePicker
from slic.devices.xdiagnostics.intensitymonitor import IntensityMonitorPBPS
from .Cristallina_mono import CristallinaMono
from .alignment_laser import AlignmentLaser
from slic.devices.xoptics.kb import KBHor, KBVer
from slic.devices.xoptics.offsetmirrors import OffsetMirror
from .pp_shutter import PP_Shutter
@ -27,7 +28,7 @@ test_attenuators()
# Shutter
pp_shutter = PP_Shutter(
"SARES30-LTIM01-EVR0:RearUniv0-Ena-SP", name="Cristallina pulse picker shutter"
) # Shutter button when using the pulse picker
) # Shutter button when ufasing the pulse picker
pulsepicker = PulsePicker(
@ -59,3 +60,10 @@ pbps149 = IntensityMonitorPBPS(
# KB mirrors
kbHor = KBHor("SAROP31-OKBH154", description="Cristallina horizontal KB mirror")
kbVer = KBVer("SAROP31-OKBV153", description="Cristallina vertical KB mirror")
# Mono
mono = CristallinaMono("SAROP31-ODCC110")
# Offset mirrors
m3 = OffsetMirror('SAROP31-ODMV152')
#TODO the other two offset mirros

0
beamline/kb_focusing.py Normal file → Executable file
View File

605
beamline/photon_energy.py Executable file
View File

@ -0,0 +1,605 @@
import time
from time import sleep
import numpy as np
from epics import PV
from logzero import logger as log
from slic.core.adjustable import Adjustable, PVAdjustable, PVEnumAdjustable
from slic.core.scanner.scanbackend import wait_for_all # , stop_all
import subprocess
UND_NAME_FMT = "SARUN{:02}-UIND030"
N_UND_CHIC = None
N_UNDS = list(range(3, 15 + 1))
# N_UNDS.remove(N_UND_CHIC) # does not exist
# offsets fro undulators, PSSS and DCCM
# convention: energy_device = energy_master - energy_offset_device
# readback_energy is energy_undulator + offset_undulator
# move the PSSS motor and the DCCM motor according to the energy_master
# TODO: improve this hack
### SETTINGS ####
PSSS_MOVE = True
DCCM_MOVE = True
TRAJECTORY_FEEDBACK_DISABLE_ENABLE = False
POINTING_FEEDFORWARD = False
energy_offset_undulators = -14 # eV
energy_offset_PSSS = -14 # eV
energy_offset_DCCM = -12 # eV
DCCM_RX2_energy_offset = 25.8 # eV
################
def print_configuration():
print(f"PSSS_MOVE = {PSSS_MOVE}")
print(f"DCCM_MOVE = {DCCM_MOVE}")
print(f"TRAJECTORY_FEEDBACK_DISABLE_ENABLE = {TRAJECTORY_FEEDBACK_DISABLE_ENABLE}")
print(f"POINTING_FEEDFORWARD = {POINTING_FEEDFORWARD}")
print(f"Undulator energy offset = {energy_offset_undulators}")
print(f"PSSS energy offset = {energy_offset_PSSS}")
print(f"DCCM energy offset = {energy_offset_DCCM}")
print(f" DCCM RX2 energy offset = {DCCM_RX2_energy_offset}")
def pointing_slope_X(energy):
#delta_X_predicted = -0.0010097 * (energy - 10000)**2 + 0.002622 * (energy - 10000) - 0.3225 # function derived from calibration energy scan
delta_X_predicted = (energy - 10000) * 10 # function derived from calibration energy scan
#pointing_X_predicted = delta_X_predicted * 0.01829+ 0.009650
pointing_X_predicted = delta_X_predicted / 113 * 4.5
return pointing_X_predicted
def pointing_slope_Y(energy):
#delta_Y_predicted = ...
delta_Y_predicted = (energy - 10000) * 10 # function derived from calibration energy scan
#pointing_Y_predicted = ...
pointing_Y_predicted = delta_Y_predicted / 113 * 4.5
return pointing_Y_predictedS
def set_PSSS_energy(energy: float):
"""When scanning the energy with the undulator we
adjust the spectrometer to follow.
"""
print(f"Adjusting PSSS to {energy}")
PSSS_energy_PV_name = "SARFE10-PSSS059:ENERGY"
PSSS_energy_PV = PV(PSSS_energy_PV_name)
PSSS_energy_PV.put(energy, wait=True)
ret = subprocess.run(["python", "/sf/photo/src/PSSS_motor/qt/PSSS_motion.py", "-s", "-m5", "SARFE10-PSSS059"])
sleep(2)
if ret.returncode != 0:
log.warning("WARNING: PSSS adjustment failed.")
else:
print("Finished adjusting PSSS.")
def set_DCCM_energy(energy: float):
"""When scanning the energy with the undulator we
adjust the monochromator to follow.
"""
print(f"Adjusting DCCM to {energy}")
DCCM_energy_PV_name = "SAROP31-ODCC110:MOT_ENY"
DCCM_energy_PV = PV(DCCM_energy_PV_name)
DCCM_energy_offset_PV_name = "SAROP31-ODCC110:MOT_OFS"
DCCM_energy_offset_PV = PV(DCCM_energy_offset_PV_name)
DCCM_energy_offset_PV.put(DCCM_RX2_energy_offset, wait=True)
DCCM_energy_PV.put(energy, wait=False)
DCCM_energy_offset_PV.put(DCCM_RX2_energy_offset, wait=False)
print(f"Finished adjusting DCCM.")
sleep(0.2)
def enable_trajectory_feedback():
print(f"Enabling trajectory FB")
TrFB_PV_name = "SFB_POINTING_AR:ONOFF1"
TrFB_PV = PV(TrFB_PV_name)
TrFB_PV.put("ON")
sleep(0.2)
def disable_trajectory_feedback():
print(f"Disabling trajectory FB")
TrFB_PV_name = "SFB_POINTING_AR:ONOFF1"
TrFB_PV = PV(TrFB_PV_name)
TrFB_PV.put("OFF")
sleep(0.2)
def set_pointing(energy):
print(f"Pointing correction")
PointingSlopeX_PV_name = "SGE-HL-FPAR:X-SLOPE1"
PointingSlopeY_PV_name = "SGE-HL-FPAR:Y-SLOPE1"
PointingSlopeX_PV = PV(PointingSlopeX_PV_name)
PointingSlopeY_PV = PV(PointingSlopeY_PV_name)
PointingSlopeX = pointing_slope_X(energy)
PointingSlopeY = pointing_slope_Y(energy)
print(f" X-slope = {PointingSlopeX} um")
print(f" Y-slope = {PointingSlopeY} um")
PointingSlopeX_PV.put(PointingSlopeX)
PointingSlopeY_PV.put(PointingSlopeY)
sleep(0.2)
class PhotonEnergy(Adjustable):
"""
for n_und_ref=None (default), the reference undulator currently used by the machine will be used
"""
def __init__(
self, n_unds=N_UNDS, n_und_ref=None, scaled=True, ID="ARAMIS_UNDULATORS", name="Aramis Undulators", units="eV"
):
# # don't allow setting these since there's no chic :)
# chic_fudge_offset = 0
# adjust_chic = False
super().__init__(ID, name=name, units=units)
machine_n_und_ref = get_machine_n_und_ref()
if n_und_ref is None:
if machine_n_und_ref is None:
raise ValueError(
f"could not read reference undulator currently used by the machine, please specify n_und_ref"
)
n_und_ref = machine_n_und_ref
if n_und_ref != machine_n_und_ref:
log.warning(
f"the chosen reference undulator ({n_und_ref}) is not the reference undulator currently used by the machine ({machine_n_und_ref})"
)
n_unds = list(n_unds)
if N_UND_CHIC in n_unds:
log.warning(
f"the CHIC ({N_UND_CHIC}) is in the list of active undulators: {n_unds}, and will be ignored/removed"
)
n_unds.remove(N_UND_CHIC)
if n_und_ref not in n_unds:
raise ValueError(f"the reference undulator ({n_und_ref}) is not in the list of active undulators: {n_unds}")
self.n_unds = n_unds
self.n_und_ref = n_und_ref
self.und_names = und_names = [UND_NAME_FMT.format(n) for n in n_unds]
self.und_name_cal = und_name_cal = UND_NAME_FMT.format(n_und_ref)
self.adjs = {name: Undulator(name) for name in und_names}
# self.chic = CHIC(chic_fudge_offset, name, units)
# self.phases = Phases(n_unds)
# self.adjust_chic = adjust_chic
self.scaled = scaled
self.convert = ConverterEK()
a = self.adjs[und_name_cal]
self.scale = ScalerEK(a)
def set_target_value(self, energy_master, hold=False):
value = energy_master + energy_offset_undulators
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():
if not DCCM_MOVE:
print("no DCCM movement enabled")
else:
energy_DCCM = energy_master + energy_offset_DCCM
set_DCCM_energy(energy_DCCM)
if not TRAJECTORY_FEEDBACK_DISABLE_ENABLE:
print("No trajectory feedback disabling performed.")
else:
disable_trajectory_feedback()
print(f"Setting undulator energy to {value}")
# 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)
# # make sure new K values have been written TODO: needed?
# sleep(2) # check if this can be shortened back to 0.5
# # switching on radial motors ...
# wait_for_all([
# a.adj_radial_on.set_target_value(1, hold=False) for a in self.adjs.values()
# ])
# # press a few times
# for _ in range(3):
# # ... and pushing go to ensure proper movements
# wait_for_all([
# a.adj_radial_go.set_target_value(1, hold=False) for a in self.adjs.values()
# ])
# sleep(0.2)
# # make sure the undulators finished moving TODO: needed?
# sleep(5)
# if self.adjust_chic:
# print("CHIC adjustment follows")
## self.chic.set_target_value(value, hold=False).wait() #TODO: test whether an additional sleep is needed
# self.phases.set(value)
# print("CHIC adjustment done")
# else:
# print("CHIC adjustment skipped")
# make sure the undulators and phases finished moving TODO: needed?
sleep(5)
if not PSSS_MOVE:
print("no PSSS movement enabled")
else:
energy_PSSS = energy_master + energy_offset_PSSS
print(f"Adjusting PSSS to {energy_PSSS}")
set_PSSS_energy(energy_PSSS)
if not POINTING_FEEDFORWARD:
print("No pointing correction performed.")
else:
set_pointing(energy_master)
if not TRAJECTORY_FEEDBACK_DISABLE_ENABLE:
print("No trajectory feedback enabling performed.")
else:
enable_trajectory_feedback()
return self._as_task(change, hold=hold)
def get_current_value(self):
n = self.und_name_cal
a = self.adjs[n]
k = a.get_current_value()
energy = self.convert.E(k) - energy_offset_undulators
# 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 # if we need to fudge the number to match the mono, do it here!
def get_current_value_undulators_real(self):
n = self.und_name_cal
a = self.adjs[n]
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 # if we need to fudge the number to match the mono, do it here!
def get_current_value_DCCM(self):
DCCM_energy_PV_name = "SAROP31-ODCC110:MOT_ENY"
DCCM_energy_PV = PV(DCCM_energy_PV_name)
energy = DCCM_energy_PV.get() - energy_offset_DCCM
return energy
def get_current_value_DCCM_real(self):
DCCM_energy_PV_name = "SAROP31-ODCC110:MOT_ENY"
DCCM_energy_PV = PV(DCCM_energy_PV_name)
energy = DCCM_energy_PV.get()
return energy
def get_current_value_PSSS(self):
PSSS_energy_PV_name = "SARFE10-PSSS059:ENERGY"
PSSS_energy_PV = PV(PSSS_energy_PV_name)
energy = PSSS_energy_PV.get() - energy_offset_PSSS
return energy
def get_current_value_PSSS_real(self):
PSSS_energy_PV_name = "SARFE10-PSSS059:ENERGY"
PSSS_energy_PV = PV(PSSS_energy_PV_name)
energy = PSSS_energy_PV.get()
return energy
def print_energies_with_offset_correction(self):
print("Real photon energies with offset correction")
print(f" Undulator = {self.get_current_value()} eV")
print(f" PSSS = {self.get_current_value_PSSS()} eV")
print(f" DCCM = {self.get_current_value_DCCM()} eV")
def print_energies(self):
print("Real photon energies")
print(f" Undulator = {self.get_current_value_undulators_real()} eV")
print(f" PSSS = {self.get_current_value_PSSS_real()} eV")
print(f" DCCM = {self.get_current_value_DCCM_real()} eV")
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 = pvname_setvalue # name + ":K_READ" #TODO: there are no readback values?
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)
# self.adj_radial_on = PVAdjustable(name + ":RADIAL-ON", internal=True) #TODO: do not exist
# self.adj_radial_go = PVAdjustable(name + ":RADIAL-GO", internal=True) #TODO: do not exist
# self.adj_radial_on_proc = PVAdjustable(name + ":RADIAL-ON.PROC", internal=True)
# self.adj_radial_go_proc = PVAdjustable(name + ":RADIAL-GO.PROC", 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 = 15e-3 # m
const = 2 * h * c / lambda_u # eV
electron_rest_energy = 0.51099895 # MeV
# was: pvname_electron_energy="SATCL01-MBND100:P-READ"
# was: pvname_electron_energy="SATCB01:ENE-FILT-OP"
def __init__(self, pvname_electron_energy="SARCL02-MBND100:P-READ"): # S30CB13:ENE-FILT-OP
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, fudge_offset, name, units):
# self.fudge_offset = fudge_offset
# 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 = self.fudge_offset
# 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
# class TwoColorChicane(PVAdjustable):
#
# def __init__(self, name):#, t0=0):
## self.t0 = t0
## name += " Two Color Chicane"
# super().__init__("SATUN14-MBND100:I-SET", "SATUN14-MBND100:I-READ", process_time=1, name=name)
#
## def set_target_value(self, value, hold=False):
## super().set_target_value(value)
#
## def get_current_value(self):
## return super().get_current_value()
# class Phases:
#
# def __init__(self, n_unds=N_UNDS):
# # 22 does not have a chicane
# n_unds = n_unds.copy()
# if 22 in n_unds:
# n_unds.remove(22)
#
# # 22 does not have a chicane
# n_unds_all = N_UNDS.copy()
# if 22 in n_unds_all:
# n_unds_all.remove(22)
#
# self.cb_auto_good = {i: PV(f"SATUN{i:02}-CHIC:AUTO-PHASING") for i in n_unds}
# self.cb_auto_bad = {i: PV(f"SATUN{i:02}-CHIC:AUTO-PHASING") for i in set(n_unds_all) - set(n_unds)}
#
# self.pv_fixed_energy = PV("SATUN-CHIC:FIX_PHOTON_ENERGY")
# self.pv_energy = PV("SATUN-CHIC:PHOTON-ENERGY")
#
#
# def set(self, energy):
# for cb in self.cb_auto_good.values(): cb.put(int(False))
# for cb in self.cb_auto_bad.values(): cb.put(int(False))
# sleep(0.1)
#
# pv_fixed_energy = self.pv_fixed_energy
#
# current_state = pv_fixed_energy.get()
# pv_fixed_energy.put(int(True)) # enforce fixed energy
#
# self.pv_energy.put(energy / 1000) # in keV
# sleep(0.1)
#
# for cb in self.cb_auto_good.values(): cb.put(int(True))
# sleep(0.1)
#
# for cb in self.cb_auto_good.values(): cb.put(int(False))
# for cb in self.cb_auto_bad.values(): cb.put(int(False))
# sleep(0.1)
#
## pv_fixed_energy.put(current_state) # reset to original state
# class Phases:
# def __init__(self, n_unds=N_UNDS):
# # 22 does not have a chicane
# n_unds = n_unds.copy()
# if 22 in n_unds:
# n_unds.remove(22)
# self.pv_energy = PV("SATUN-CHIC:PHOTON-ENERGY")
# self.pv_fixed_energy = PV("SATUN-CHIC:FIX_PHOTON_ENERGY")
# self.adjs_apply = {i: PVAdjustable(f"SATUN{i:02}-CHIC:APPLY-DOP", internal=True) for i in n_unds}
# def set(self, energy):
# pv_energy = self.pv_energy
# pv_fixed_energy = self.pv_fixed_energy
# current_state = pv_fixed_energy.get()
# pv_fixed_energy.put(int(True)) # enforce fixed energy
# pv_energy.put(energy / 1000) # in keV
# sleep(0.1)
# self.update()
## sleep(10)
# pv_fixed_energy.put(current_state) # reset to original state
# def update(self):
# wait_for_all([
# adj_apply.set_target_value(1) for adj_apply in self.adjs_apply.values()
# ])
def get_machine_n_und_ref():
for attempt in range(3):
try:
res = PVEnumAdjustable("SARUN:REF-UND").get()
if not res.startswith("SARUN"):
return None
except AttributeError as e:
print("Error getting undulator, retrying")
print(e)
time.sleep(1)
else:
break
n = len("SARUN")
res = res[n:]
try:
res = int(res)
except ValueError:
return None
return res

0
beamline/pp_shutter.py Normal file → Executable file
View File

0
beamline/pulse_picker.py Normal file → Executable file
View File

4
beamline/undulator.py Normal file → Executable file
View File

@ -23,8 +23,8 @@ N_UNDS = list(range(3, 15 + 1))
# Cristallina without calibration
# offset is the difference between PSSS and undulator setpoint
# sign convention: Undulator - PSSS
energy_offset = -70 # eV
energy_offset = 0 # eV
# PSSS = 8355 eV, machine = 8253 eV
# move the PSSS motor according to the energy
# TODO: improve this hack

BIN
channels/.pv_channels.py.swp Executable file

Binary file not shown.

287
channels/bs_channels.py Normal file → Executable file
View File

@ -1,18 +1,17 @@
# Channels to save at Cristallina endstation
##########################################################################################################
##########################################################################################################
##########################################################################################################
# BS channels
### JUNGFRAU DETECTORS
from slic.core.acquisition.detcfg import DetectorConfig
# TODO: JF settings regarding raw conversion, compression, etc.
detectors = [
"JF16T03V02",
# "JF16T03V01",
# "JF17T16V01",
"JF20T01V01",
"JF16T03V02", # 1.5M from 2025
# "JF16T03V01", # 1.5M from 2022
# "JF17T16V01", # 8M
"JF20T01V01", # IO
# "JF05T01V01", # 0.5M stripsel borrowed from Bernina, now registered in esc network
]
# ALLOWED_PARAMS = dict(
@ -53,26 +52,35 @@ detectors = DetectorConfig(detectors)
detectors_MX = DetectorConfig()
detectors_MX.add("JF17T16V01", adc_to_energy=True, compression=True, crystfel_lists_laser=True, double_pixels_action="mask", factor=11.00, remove_raw_files=True, save_dap_results=True, geometry=True)
detectors_MX.add("JF17T16V01", adc_to_energy=True, compression=True, crystfel_lists_laser=True, double_pixels_action="mask", factor=12.00, remove_raw_files=True, save_dap_results=True, geometry=False)
##########################################################################################################
##########################################################################################################
##########################################################################################################
### BS CHANNELS
###########################################################################
#### CAMERAS COLLECTED
camera_channels = [
# "SARES30-CAMS156-PCO1:FPICTURE", # PCO edge camera for the wavefront analysis (from Alvra)
# "SARES30-CAMS156-SMX-OAV:FPICTURE", # SwissMX OAV camera picture
# "SARES30-CAMS156-SMX-OAV.jet_projection", #SWISSMX oav jET PROJECTION
# "SARES30-CAMS156-SMX-OAV:FPICTURE", # SwissMX OAV camera picture
# "SARES30-CAMS156-SMX-OAV.jet_projection", #SWISSMX oav jET PROJECTION
# "SARES30-CAMS156-XE:FPICTURE", # X-ray eye
]
####################
# Machine gas intensity monitor
channels_gas_monitor = [
"SARFE10-PBPG050:PHOTON-ENERGY-PER-PULSE-AVG",
# "SARFE10-PBPG050:SLOW-X",
# "SARFE10-PBPG050:SLOW-Y",
"SARFE10-PBIG050-EVR0:CALCI", # good for correlations with total beam intensity
"SARFE10-PBPG050:HAMP-INTENSITY-CAL",
]
###########################################################################
#### MACHINE
# RF phases and amplitudes
channels_RF = [
@ -145,36 +153,38 @@ channels_RF = [
"S30CB14-RLLE-DSP:AMPLT-VS",
]
channels_Xeye = ["SARES30-CAMS156-XE:intensity",
"SARES30-CAMS156-XE:x_center_of_mass",
"SARES30-CAMS156-XE:x_fit_amplitude",
"SARES30-CAMS156-XE:x_fit_mean",
"SARES30-CAMS156-XE:x_fit_offset",
"SARES30-CAMS156-XE:x_fit_standard_deviation",
"SARES30-CAMS156-XE:x_fwhm",
"SARES30-CAMS156-XE:x_profile",
"SARES30-CAMS156-XE:x_rms",
"SARES30-CAMS156-XE:y_center_of_mass",
"SARES30-CAMS156-XE:y_fit_amplitude",
"SARES30-CAMS156-XE:y_fit_mean",
"SARES30-CAMS156-XE:y_fit_offset",
"SARES30-CAMS156-XE:y_fit_standard_deviation",
"SARES30-CAMS156-XE:y_fwhm",
"SARES30-CAMS156-XE:y_profile",
"SARES30-CAMS156-XE:y_rms",
# "SARES30-CAMS156-XE:FPICTURE",
]
######################
# PBPS053
###########################################################################
#### FRONT-END
####################
# Gas intensity monitor PBPG050
channels_gas_monitor = [
"SARFE10-PBPG050:PHOTON-ENERGY-PER-PULSE-AVG",
# "SARFE10-PBPG050:SLOW-X",
# "SARFE10-PBPG050:SLOW-Y",
"SARFE10-PBIG050-EVR0:CALCI", # good for correlations with total beam intensity
"SARFE10-PBPG050:HAMP-INTENSITY-CAL",
]
###################
# Beam position and intensity monitor PBPS053
channels_PBPS053 = [
"SARFE10-PBPS053:INTENSITY",
"SARFE10-PBPS053:XPOS",
"SARFE10-PBPS053:YPOS",
]
####################
# PSSS059
###################
# Spectrometer PSSS059
channels_PSSS059 = [
"SARFE10-PSSS059:FIT-COM",
"SARFE10-PSSS059:FIT-FWHM",
@ -190,7 +200,9 @@ channels_PSSS059 = [
"SARFE10-PSSS059:processing_parameters",
]
# Large bandwidth camera
###################
# Spectrometer PSSS059, large bandwidth camera
channels_PSSS059_LB = [
"SARFE10-PSSS059-LB:FIT-COM",
"SARFE10-PSSS059-LB:FIT-FWHM",
@ -207,18 +219,13 @@ channels_PSSS059_LB = [
"SARFE10-PSSS059-LB:FIT-BRT",
]
###################################
## Bernina channels
# Beam position monitor PBPS113
#channels_Bernina = [
# "SAROP21-PBPS103:INTENSITY",
# "SAROP21-PBPS103:XPOS",
# "SAROP21-PBPS103:YPOS",
# #"SAROP21-PPRM113:FPICTURE",
# "SAROP21-PPRM113:intensity",
# "SAROP21-PPRM113:x_fit_mean",
# "SAROP21-PPRM113:y_fit_mean",
#]
###########################################################################
#### BERNINA BRANCH until DCM
###################
# Bernina beam intensity and position monitor PBPS113 (alias PBPS103)
channels_PBPS113_bernina = [
"SAROP21-PBPS103:INTENSITY",
@ -231,6 +238,10 @@ channels_PBPS113_bernina = [
"SAROP21-PBPS103:YPOS",
]
###################
# Bernina screen PPRM113
channels_PPRM113_bernina = [
"SAROP21-PPRM113:intensity",
"SAROP21-PPRM113:x_center_of_mass",
@ -253,8 +264,15 @@ channels_PPRM113_bernina = [
]
###################################
# Beam position monitor PBPS113
###########################################################################
#### CRISTALLINA BRANCH
###################
## Beam position and intensity monitor PBPS113
channels_PBPS113 = [
"SAROP31-PBPS113:INTENSITY",
"SAROP31-PBPS113:INTENSITY_UJ",
@ -262,11 +280,11 @@ channels_PBPS113 = [
"SAROP31-PBPS113:Lnk9Ch0-PP_VAL_PD1",
"SAROP31-PBPS113:Lnk9Ch0-PP_VAL_PD2",
"SAROP31-PBPS113:Lnk9Ch0-PP_VAL_PD3",
"SAROP31-PBPS113:Lnk9Ch0-PP_VAL_PD4",
"SAROP31-PBPS113:XPOS",
"SAROP31-PBPS113:YPOS",
]
# purpose?
channels_PBPS113_waveforms = [
"SAROP31-PBPS113:Lnk9Ch0-WF-DATA",
"SAROP31-PBPS113:Lnk9Ch1-WF-DATA",
@ -286,8 +304,18 @@ channels_PBPS113_waveforms = [
"SAROP31-PBPS113:Lnk9Ch15-WF-DATA",
]
####################
# Profile monitor PPRM113 (from _proc process)
###################
# Diode PDIM113
channels_PDIM113 = [
"SAROP31-PBPS113:Lnk9Ch0-PP_VAL_PD4",
]
###################
# Beam profile monitor PPRM113
channels_PPRM113 = [
"SAROP31-PPRM113:intensity",
"SAROP31-PPRM113:x_center_of_mass",
@ -309,13 +337,10 @@ channels_PPRM113 = [
# "SAROP31-PPRM113:FPICTURE", # full pictures for debugging purposes at the moment, from _ib process
]
###########################
# Beam position monitor PBPS149
# "SARES30-CAMS156-PCO1:FPICTURE", # PCO edge camera for the wavefront analysis (from Alvra)
# "SARES30-CAMS156-SMX-OAV:FPIC
###########################
# Beam position monitor
###################
# Beam position and intensity monitor PBPS149
channels_PBPS149 = [
"SAROP31-PBPS149:INTENSITY",
"SAROP31-PBPS149:INTENSITY_UJ",
@ -327,6 +352,7 @@ channels_PBPS149 = [
"SAROP31-PBPS149:YPOS",
]
#######################
# Profile monitor PPRM150 (from _proc process)
channels_PPRM150 = [
@ -350,14 +376,32 @@ channels_PPRM150 = [
# "SAROP31-PPRM150:FPICTURE", # full pictures for debugging purposes at the moment, from _ib process
]
####################
# Diode under screen between the KB's PSCD153
channels_PSCD153 = [
"SAROP31-PBPS149:Lnk9Ch0-PP_VAL_PD4",
]
###########################################################################
#### GENERAL PURPOSE EXPERIMENT
#######################
# Cristallina event reciever
channels_EVR = [
"SAR-CVME-TIFALL6:EvtSet",
]
#######################
# Digitizer
channels_digitizer = [
# extra non-beam synchronous channels:
#"SARES30-LTIM01-EVR0:DUMMY_PV1_NBS",
@ -366,37 +410,126 @@ channels_digitizer = [
#"SARES30-LTIM01-EVR0:DUMMY_PV4_NBS",
# other EVR channels:
"SARES30-LSCP1-FNS:CH0:VAL_GET", # Signal-Background
"SARES30-LSCP1-FNS:CH1:VAL_GET", # Signal-Background
"SARES30-LSCP1-FNS:CH2:VAL_GET", # Signal-Background
"SARES30-LSCP1-FNS:CH3:VAL_GET", # Signal-Background
"SARES30-LSCP1-FNS:CH4:VAL_GET", # Signal-Background
"SARES30-LSCP1-FNS:CH5:VAL_GET", # Signal-Background
"SARES30-LSCP1-FNS:CH6:VAL_GET", # Signal-Background
"SARES30-LSCP1-FNS:CH7:VAL_GET", # Signal-Background
"SARES30-LSCP1-CRISTA1:CH0:1", # Waveform signal
"SARES30-LSCP1-CRISTA1:CH2:1", # Waveform trigger
"SARES30-LSCP1-CRISTA1:CH1:1", # Waveform signal
"SARES30-LSCP1-CRISTA1:CH2:1", # Waveform signal
"SARES30-LSCP1-CRISTA1:CH3:1", # Waveform signal
"SARES30-LSCP1-CRISTA1:CH4:1", # Waveform signal
"SARES30-LSCP1-CRISTA1:CH5:1", # Waveform signal
"SARES30-LSCP1-CRISTA1:CH6:1", # Waveform signal
"SARES30-LSCP1-CRISTA1:CH7:1", # Waveform signal
# "SARES30-LSCP1-CRISTA1:CH2:1", # Waveform trigger
"SARES30-LTIM01-EVR0:CALCI", # Calculated intensity
]
#######################
# Other BS channels that we sometimes use
channels_other = [
# "SARFE10-PPRM053:FPICTURE", # TODO: Test if this works here
# "SARFE10-PPRM064:FPICTURE", # TODO: Test if this works here
]
# X-ray eye
channels_Xeye = [
"SARES30-CAMS156-XE:intensity",
"SARES30-CAMS156-XE:x_center_of_mass",
"SARES30-CAMS156-XE:x_fit_amplitude",
"SARES30-CAMS156-XE:x_fit_mean",
"SARES30-CAMS156-XE:x_fit_offset",
"SARES30-CAMS156-XE:x_fit_standard_deviation",
"SARES30-CAMS156-XE:x_fwhm",
"SARES30-CAMS156-XE:x_profile",
"SARES30-CAMS156-XE:x_rms",
"SARES30-CAMS156-XE:y_center_of_mass",
"SARES30-CAMS156-XE:y_fit_amplitude",
"SARES30-CAMS156-XE:y_fit_mean",
"SARES30-CAMS156-XE:y_fit_offset",
"SARES30-CAMS156-XE:y_fit_standard_deviation",
"SARES30-CAMS156-XE:y_fwhm",
"SARES30-CAMS156-XE:y_profile",
"SARES30-CAMS156-XE:y_rms",
# "SARES30-CAMS156-XE:FPICTURE",
]
###########################################################################
#### CRISTALLINA-Q EXPERIMENT
#######################
# Diffractometer 1 bs_channels
ID_dm1 = "SARES31-GPS"
diffractometer_1_bs = [
ID_dm1 + ":ROT2THETA-BS",
ID_dm1 + ":ROTTHETA-BS",
ID_dm1 + ":TRX-BS",
ID_dm1 + ":TRY-BS",
ID_dm1 + ":TRZ-BS",
ID_dm1 + ":TD-BS",
ID_dm1 + ":TRXBASE-BS",
ID_dm1 + ":TRYBASE-BS",
ID_dm1 + ":TRYBASE-Avg-BS",
ID_dm1 + "::CALC1",
ID_dm1 + "::CALC2",
ID_dm1 + "::CALC3",
ID_dm1 + "::CALC4",
]
###########################################################################
#### CHANNEL GROUPS
bs_channels = (
camera_channels
+ channels_gas_monitor
channels_gas_monitor
# + channels_RF
+ channels_Xeye
+ channels_PBPS053
+ channels_PSSS059
+ channels_PSSS059_LB
+ channels_PBPS113
# + channels_PBPS113_waveforms
+ channels_PDIM113
# + channels_PPRM113
+ channels_PBPS149
# + channels_PBPS149_waveforms
# + channels_PPRM150 # only if screen is inserted
+ channels_PSCD153
+ channels_EVR
# + channels_digitizer
+ channels_other
+ channels_digitizer
# + channels_Xeye
# + diffractometer_1_bs
# + camera_channels
)
bs_channels_cristallina_beamline = (
channels_gas_monitor
# + channels_RF
+ channels_PBPS053
+ channels_PSSS059
+ channels_PSSS059_LB
+ channels_PBPS113
# + channels_PBPS113_waveforms
+ channels_PDIM113
# + channels_PPRM113
+ channels_PBPS149
# + channels_PBPS149_waveforms
# + channels_PPRM150 # only if screen is inserted
+ channels_PSCD153
+ channels_EVR
)
bs_channels_bernina_DCM = (
channels_gas_monitor
# + channels_RF

496
channels/pv_channels.py Normal file → Executable file
View File

@ -1,15 +1,15 @@
##########################################################################################################
##########################################################################################################
##########################################################################################################
# Epics PVS
### EPICS PVS
###########################################################################
#### MACHINE
# Compression, charge settings
#######################
# Machine
pvs_machine = [
"SARCL02-MBND100:P-READ", # Predicted bunch energy
"SARUN:FELPHOTENE.VAL", # Predicted photon energy from machine settings
"SARFE10-PBPG050:PHOTON-ENERGY-PER-PULSE-AVG.VAL", # Average pulse energy from the gas detector
]
# accelerator parameters
@ -83,8 +83,10 @@ pvs_RF = [
"S30CB14-RSYS:GET-VSUM-AMPLT-SCALE",
]
#######################
# Undulator gap
pvs_undulator = [
"SARUN03-UIND030:K_SET.VAL",
"SARUN04-UIND030:K_SET.VAL",
@ -99,17 +101,24 @@ pvs_undulator = [
"SARUN13-UIND030:K_SET.VAL",
"SARUN14-UIND030:K_SET.VAL",
"SARUN15-UIND030:K_SET.VAL",
"SFB_POINTING_AR:SP1",
"SFB_POINTING_AR:SP2",
"SFB_POINTING_AR:ONOFF1",
"SGE-HL-FPAR:X-SLOPE1",
"SGE-HL-FPAR:Y-SLOPE1",
"SGE-HL-FPAR:X-OFFSET1",
"SGE-HL-FPAR:Y-OFFSET1",
]
####################
# Machine gas intensity monitor
pvs_gas_monitor = [
"SARFE10-PBPG050:PHOTON-ENERGY-PER-PULSE-US",
"SARFE10-PBPG050:PHOTON-ENERGY-PER-PULSE-DS",
]
###########################################################################
#### FRONT-END
#####################
# Slits OAPU044
pvs_OAPU044 = [
"SARFE10-OAPU044:MOTOR_X",
"SARFE10-OAPU044:MOTOR_Y",
@ -117,37 +126,30 @@ pvs_OAPU044 = [
"SARFE10-OAPU044:MOTOR_H",
]
####################
# Gas intensity monitor PBPG050
pvs_gas_monitor = [
"SARFE10-PBPG050:PHOTON-ENERGY-PER-PULSE-US",
"SARFE10-PBPG050:PHOTON-ENERGY-PER-PULSE-DS",
"SARFE10-PBPG050:PHOTON-ENERGY-PER-PULSE-AVG",
]
###################
# Beam position monitor PBPS053
# Beam position and intensity monitor PBPS053
pvs_PBPS053 = [
"SARFE10-PBPS053:MOTOR_X1",
# "SARFE10-PBPS053:MOTOR_X2", # Not available, disabled
"SARFE10-PBPS053:MOTOR_PROBE",
]
###################
# Spectrometer PSSS059
pvs_PSSS059 = [
"SARFE10-PSSS055:MOTOR_X1.RBV",
"SARFE10-PSSS055:MOTOR_Y1.RBV",
"SARFE10-PSSS055:MOTOR_ROT_X1.RBV",
"SARFE10-PSSS055:MOTOR_PROBE.RBV",
"SARFE10-PSSS059:MOTOR_X3.RBV",
"SARFE10-PSSS059:MOTOR_Y3.RBV",
"SARFE10-PSSS059:MOTOR_ROT_X3.RBV",
"SARFE10-PSSS059:MOTOR_Y4.RBV",
"SARFE10-PSSS059:MOTOR_ROT_X4.RBV",
"SARFE10-PSSS059:MOTOR_X5.RBV",
"SARFE10-PSSS059:MOTOR_Y5.RBV",
"SARFE10-PSSS059:MOTOR_Z5.RBV",
"SARFE10-PSSS055:GRATING_SP",
"SARFE10-PSSS059:CRYSTAL_SP",
"SARFE10-PSSS059:SPC_ROI_YMIN",
"SARFE10-PSSS059:SPC_ROI_YMAX",
]
####################
# Upstream attenuator OATT053
pvs_OATT053_old = [
"SARFE10-OATT053:MOTOR_1",
"SARFE10-OATT053:MOTOR_1.RBV",
@ -169,6 +171,7 @@ pvs_OATT053_old = [
####################
# New Upstream attenuator OATT053
pvs_OATT053 = [
"SARFE10-OATT053:photonenergy", # Photon energy for Transmission
"SARFE10-OATT053:transmission", # Total Transmission of all stages
@ -183,38 +186,98 @@ pvs_OATT053 = [
"SARFE10-OATT053:MOTOR_6", # motor Motor 6
]
###################
# Beam profile monitor PPRM053
pvs_PPRM053 = [
"SARFE10-PPRM053:MOTOR_PROBE.RBV",
#"SARFE10-PPRM053:FPICTURE",
#"SARFE10-PPRM064:FPICTURE", # TODO move to correct place
]
###################
# Bernina mono
#pvs_Bernina = [
# "SAROP21-ARAMIS:ENERGY_SP",
# "SAROP21-ARAMIS:ENERGY",
# "SAROP21-PBPS103:MOTOR_X1.DRBV",
# "SAROP21-PBPS103:MOTOR_Y1.DRBV",
# "SAROP21-PBPS103:MOTOR_X1.RBV",
# "SAROP21-PBPS103:MOTOR_Y1.RBV",
# "SAROP21-PBPS103:MOTOR_PROBE.RBV",
# "SAROP21-PPRM113:MOTOR_PROBE.RBV"
#]
# Diode PDIM053
# pvs_PDIM053 = [
# ]
###################
# Spectrometer PSSS059
pvs_PSSS059 = [
"SARFE10-PSSS055:MOTOR_X1.RBV",
"SARFE10-PSSS055:MOTOR_Y1.RBV",
"SARFE10-PSSS055:MOTOR_ROT_X1.RBV",
"SARFE10-PSSS055:MOTOR_PROBE.RBV",
"SARFE10-PSSS059:MOTOR_X3.RBV",
"SARFE10-PSSS059:MOTOR_Y3.RBV",
"SARFE10-PSSS059:MOTOR_ROT_X3.RBV",
"SARFE10-PSSS059:MOTOR_Y4.RBV",
"SARFE10-PSSS059:MOTOR_ROT_X4.RBV",
"SARFE10-PSSS059:MOTOR_X5.RBV",
"SARFE10-PSSS059:MOTOR_Y5.RBV",
"SARFE10-PSSS059:MOTOR_Z5.RBV",
"SARFE10-PSSS055:GRATING_SP",
"SARFE10-PSSS059:CRYSTAL_SP",
"SARFE10-PSSS059:SPC_ROI_YMIN",
"SARFE10-PSSS059:SPC_ROI_YMAX",
"SARFE10-PSSS055:MOTOR_PROBE.RBV",
]
###################
# PPRM064
# pvs_PPRM064 = [
# ]
###################
# Alvra M1 horizontal offset mirror
# pvs_OOMH064 = [
# ]
###################
# PPRM066
# pvs_PPRM066 = [
# ]
###########################################################################
#### BERNINA BRANCH until DCM
###################
# Bernina photon energy
pvs_photon_energy_bernina = [
"SAROP21-ARAMIS:ENERGY_SP",
"SAROP21-ARAMIS:ENERGY",
]
###################
# Bernina apertures OAPU092
pvs_OAPU092_bernina = [
"SAROP21-OAPU044:MOTOR_X.RBV",
"SAROP21-OAPU044:MOTOR_Y.RBV",
"SAROP21-OAPU044:MOTOR_W.RBV",
"SAROP21-OAPU044:MOTOR_H.RBV",
"SAROP21-OAPU092:MOTOR_X.RBV",
"SAROP21-OAPU092:MOTOR_Y.RBV",
"SAROP21-OAPU092:MOTOR_W.RBV",
"SAROP21-OAPU092:MOTOR_H.RBV",
]
###################
# Bernina M1 vertical offset mirror
pvs_OOMV092_bernina = [
"SAROP21-OOMV092:W_X.RBV",
"SAROP21-OOMV092:W_Y.RBV",
@ -228,11 +291,19 @@ pvs_OOMV092_bernina = [
"SAROP21-OOMV092:TX.RBV",
]
###################
# Bernina post-M1 screen PPRM094
pvs_PPRM094_bernina = [
"SAROP21-PPRM113:MOTOR_PROBE",
#"SAROP21-PPRM113:FPICTURE",
]
###################
# Bernina M2 vertical offset mirror
pvs_OOMV096_bernina = [
"SAROP21-OOMV096:W_X.RBV",
"SAROP21-OOMV096:W_Y.RBV",
@ -246,10 +317,18 @@ pvs_OOMV096_bernina = [
"SAROP21-OOMV096:TX.RBV",
]
###################
# Bernina post-M2 screen PSCR097
pvs_PSCR097_bernina = [
"SAROP21-PSCR097:MOTOR_Y1.RBV",
]
###################
# Bernina DCM ODCM098
pvs_ODCM098_bernina = [
"SAROP21-ODCM098:RX12.RBV", # BRAGG
"SAROP21-ODCM098:TX12.RBV", # Horizontal
@ -257,19 +336,32 @@ pvs_ODCM098_bernina = [
"SAROP21-ODCM098:RZ1.RBV", # 1st xtal roll
"SAROP21-ODCM098:RZ2.RBV", # 2nd xtal roll
"SAROP21-ODCM098:RX2.RBV", # 2nd xtal pitch
"SAROP21-ODCM098:ENERGY", # DCM photon energy
]
###################
# Bernina apertures OAPU102
pvs_OAPU102_bernina = [
"SAROP21-OAPU092:MOTOR_X.RBV",
"SAROP21-OAPU092:MOTOR_Y.RBV",
"SAROP21-OAPU092:MOTOR_W.RBV",
"SAROP21-OAPU092:MOTOR_H.RBV",
"SAROP21-OAPU102:MOTOR_X.RBV",
"SAROP21-OAPU102:MOTOR_Y.RBV",
"SAROP21-OAPU102:MOTOR_W.RBV",
"SAROP21-OAPU102:MOTOR_H.RBV",
]
###################
# Bernina spontaneous radiation monitor PSRD103
pvs_PSRD103_bernina = [
"SAROP21-PSRD103:MOTOR_PROBE",
]
###################
# Bernina beam intensity and position monitor PBPS113 (alias PBPS103)
pvs_PBPS113_bernina = [
"SAROP21-PBPS103:MOTOR_X1.DRBV",
"SAROP21-PBPS103:MOTOR_Y1.DRBV",
@ -279,6 +371,10 @@ pvs_PBPS113_bernina = [
"SAROP21-PPRM113:MOTOR_PROBE.RBV"
]
###################
# Bernina pulse-picker OPPI113
pvs_OPPI113_bernina = [
"SAROP21-OPPI113:MOTOR_X1.RBV", # X1 instead of X
"SAROP21-OPPI113:MOTOR_Y1.RBV", # Y1 instead of X
@ -286,13 +382,23 @@ pvs_OPPI113_bernina = [
]
pvs_PPRM113 = [
###################
# Bernina screen PPRM113
pvs_PPRM113_bernina = [
"SAROP21-PPRM113:MOTOR_PROBE.RBV",
]
###########################################################################
#### CRISTALLINA BRANCH
####################
# First Cristallina horizontal offset mirror OOMH067
# Cristallina M1 horizontal offset mirror OOMH067
pvs_OOMH067 = [
"SAROP31-OOMH067:W_X.RBV",
"SAROP31-OOMH067:W_Y.RBV",
@ -308,14 +414,17 @@ pvs_OOMH067 = [
"SAROP31-OOMH067:RY.RBV",
]
####################
# Beam screen between the first two horizontal mirrors PSCR068
pvs_PSCR068 = [
"SAROP31-PSCR068:MOTOR_PROBE.RBV",
]
####################
# Second Cristallina horizontal offset mirror OOMH084
# Cristallina M2 horizontal offset mirror OOMH084
pvs_OOMH084 = [
"SAROP31-OOMH084:W_X.RBV",
"SAROP31-OOMH084:W_Y.RBV",
@ -331,14 +440,18 @@ pvs_OOMH084 = [
"SAROP31-OOMH084:RY.RBV",
]
###################
# Beam profile monitor PPRM085
pvs_PPRM085 = [
"SAROP31-PPRM085:MOTOR_PROBE.RBV",
]
###################
# Slits OAPU107
pvs_OAPU107 = [
"SAROP31-OAPU107:MOTOR_X.VAL",
"SAROP31-OAPU107:MOTOR_X.RBV",
@ -346,8 +459,30 @@ pvs_OAPU107 = [
"SAROP31-OAPU107:MOTOR_Y.RBV",
]
###################
## Double channel-cut monochromator ODCC110
pvs_ODCC110 = [
"SAROP31-ODCC110:MOT_RX1.RBV",
"SAROP31-ODCC110:MOT_RX2.RBV",
"SAROP31-ODCC110:MOT_ENY.RBV",
"SAROP31-ODCC110:MOT_OFS.RBV",
"SAROP31-ODCC110:MOT_TX1.RBV",
]
###################
## Infra-channel-cut-crystals screen PSCR110110
pvs_PSCR110 = [
"SAROP31-PSCR110:MOT_TY1.RBV",
]
###################
## Beam position and intensity monitor PBPS113
pvs_PBPS113 = [
"SAROP31-PBPS113:MOTOR_X1.DRBV",
"SAROP31-PBPS113:MOTOR_Y1.DRBV",
@ -356,20 +491,34 @@ pvs_PBPS113 = [
"SAROP31-PBPS113:MOTOR_PROBE.RBV",
]
###################
# Diode PDIM113
pvs_PDIM113 = [
"SAROP31-PDIM113:MOTOR_PROBE.RBV",
]
###################
# Beam profile monitor PPRM113
pvs_PPRM113 = [
"SAROP31-PPRM113:MOTOR_PROBE.RBV",
]
####################
# Alignment laser mirror OLAS147
pvs_OLAS147 = [
"SAROP31-OLAS147:MOTOR_1.RBV",
]
###################
# Slits OAPU149
pvs_OAPU149 = [
"SAROP31-OAPU149:MOTOR_X.RBV",
"SAROP31-OAPU149:MOTOR_Y.RBV",
@ -377,8 +526,10 @@ pvs_OAPU149 = [
"SAROP31-OAPU149:MOTOR_H.RBV",
]
###################
# Beam position and intensity monitor PBPS149
pvs_PBPS149 = [
"SAROP31-PBPS149:MOTOR_X1.DRBV",
"SAROP31-PBPS149:MOTOR_Y1.DRBV",
@ -387,14 +538,18 @@ pvs_PBPS149 = [
"SAROP31-PBPS149:MOTOR_PROBE.RBV",
]
###################
# Beam profile monitor PPRM150
pvs_PPRM150 = [
"SAROP31-PPRM150:MOTOR_PROBE.RBV",
]
####################
# Attenuators OATA150
# Attenuators OATA150, old
pvs_OATA150_old = [
"SAROP31-OATA150:MOTOR_1.RBV",
"SAROP31-OATA150:MOTOR_2.RBV",
@ -409,8 +564,10 @@ pvs_OATA150_old = [
"SAROP31-OATA150:MOT2TRANS.VALD"
]
####################
# New Attenuators OATA150
# Attenuators OATA150
pvs_OATA150 = [
"SAROP31-OATA150:photonenergy", # ai Photon energy for Transmission SAROP31-CPCL-OSAT150 swissfel
"SAROP31-OATA150:transmission", # ai Total Transmission of all stages SAROP31-CPCL-OSAT150 swissfel
@ -429,9 +586,9 @@ pvs_OATA150 = [
]
####################
# Pulse picker OPPI151
pvs_OPPI151 = [
"SAROP31-OPPI151:MOTOR_X1.RBV", # X1 instead of X
"SAROP31-OPPI151:MOTOR_Y1.RBV", # Y1 instead of X
@ -441,6 +598,7 @@ pvs_OPPI151 = [
####################
## Horizontal offset mirror ODMV152
pvs_ODMV152 = [
"SAROP31-ODMV152:W_X.RBV",
"SAROP31-ODMV152:W_Y.RBV",
@ -454,8 +612,10 @@ pvs_ODMV152 = [
"SAROP31-ODMV152:TX.RBV",
]
###########################
# Vertical KB mirror OKBV153
pvs_OKBV153 = [
"SAROP31-OKBV153:W_X.RBV",
"SAROP31-OKBV153:W_Y.RBV",
@ -471,14 +631,18 @@ pvs_OKBV153 = [
"SAROP31-OKBV153:TX2.RBV",
]
####################
# Screen between the KB's PSCD153
pvs_PSCD153 = [
"SAROP31-PSCD153:MOTOR_PROBE.RBV"
]
###########################
# Horizontal KB mirror OKBH154
pvs_OKBH154 = [
"SAROP31-OKBH154:W_X.RBV",
"SAROP31-OKBH154:W_Y.RBV",
@ -493,16 +657,38 @@ pvs_OKBH154 = [
"SAROP31-OKBH154:TX2.RBV",
]
###########################
# Izero-slit unit
pvs_i0_chamber = [
"SARES30-MCS20610:MCS1.RBV",
"SARES30-MCS20610:MCS2.RBV",
"SARES30-MCS20610:MCS3.RBV",
"SARES30-MCS20610:MCS4.RBV",
"SARES30-MCS20610:MCS5.RBV"
]
###########################################################################
#### GENERAL PURPOSE EXPERIMENT
####################
# Standa motors (mainly used with the X-ray eye)
pvs_standa = [
"SARES30-MOBI1:MOT_1.RBV",
"SARES30-MOBI1:MOT_2.RBV",
"SARES30-MOBI1:MOT_3.RBV",
]
####################
# Newport 300 mm stage
pvs_newport_300 = [
"SARES30-MOBI1:MOT_5.RBV",
]
@ -510,6 +696,7 @@ pvs_newport_300 = [
###############################
# Smaract stages mini XYZ from SwissMX
pvs_smaract_xyz = [
"SARES30-MCS2750:MOT_1.RBV",
"SARES30-MCS2750:MOT_1.VAL",
@ -519,15 +706,19 @@ pvs_smaract_xyz = [
"SARES30-MCS2750:MOT_3.VAL",
]
####################
# Attocube motors
pvs_attocube = [
"SARES30-ATTOCUBE:A0-POS",
"SARES30-ATTOCUBE:A1-POS",
]
###############################
# Smaract stages from Juraj
pvs_smaract_juraj = [
"SARES30-XSMA156:X:MOTRBV",
"SARES30-XSMA156:Y:MOTRBV",
@ -537,30 +728,9 @@ pvs_smaract_juraj = [
"SARES30-XSMA156:Rz:MOTRBV",
]
pvs_diffractometer_1 = [
"SARES30-CPCL-ECMC02:ROT2THETA-PosAct",
"SARES30-CPCL-ECMC02:ROTTHETA-PosAct",
"SARES30-CPCL-ECMC02:TRXBASE-PosAct",
"SARES30-CPCL-ECMC02:TRY-PosAct",
"SARES30-CPCL-ECMC02:TRX-PosAct",
"SARES30-CPCL-ECMC02:TRZ-PosAct",
"SARES30-CPCL-ECMC02:TD-PosAct",
"SARES30-CPCL-ECMC02:m1s012-Drv01-TrqAct", # TRYBASE Mot 1 torque
"SARES30-CPCL-ECMC02:m1s013-Drv01-TrqAct", # TRYBASE Mot 2 torque
"SARES30-CPCL-ECMC02:m1s014-Drv01-TrqAct", # TRYBASE Mot 3 torque
"SARES30-CPCL-ECMC02:m1s015-Drv01-TrqAct", # TRYBASE Mot 4 torque
"SARES30-CPCL-ECMC02:m1s027-Drv01-TrqAct", # TD Mot torque
"SARES30-CPCL-ECMC02:m1s011-Drv01-TrqAct", # TRXBASE Mot torque
"SARES30-CPCL-ECMC02:m1s030-Drv01-TrqAct", # TRX Mot torque
"SARES30-CPCL-ECMC02:m1s031-Drv01-TrqAct", # TRY Mot torque
"SARES30-CPCL-ECMC02:m1s029-Drv01-TrqAct", # TRZ Mot torque
"SARES30-CPCL-ECMC02:m1s010-Drv01-TrqAct", # ROT2THETA Mot torque
"SARES30-CPCL-ECMC02:m1s028-Drv01-TrqAct", # ROTTHETA Mot torque
]
pvs_huber_z= [
"SARES30-MOBI2:MOT_Z.RBV",
]
###############################
# General purpose JJ-slits
pvs_JJ_slits = [
"SARES30-MOBI2:MOT_X.RBV",
@ -569,27 +739,123 @@ pvs_JJ_slits = [
"SARES30-MOBI2:MOT_H.RBV",
]
###########################################################################
#### CRISTALLINA-Q EXPERIMENT
###############################
# Diffractometer 1
ID_dm1 = "SARES31-GPS"
pvs_diffractometer_1 = [
ID_dm1 + ":ROT2THETA-PosAct",
ID_dm1 + ":ROTTHETA-PosAct",
ID_dm1 + ":TRXBASE-PosAct",
ID_dm1 + ":TRY-PosAct",
ID_dm1 + ":TRX-PosAct",
ID_dm1 + ":TRZ-PosAct",
ID_dm1 + ":TD-PosAct",
ID_dm1 + ":m1s012-Drv01-TrqAct", # TRYBASE Mot 1 torque
ID_dm1 + ":m1s013-Drv01-TrqAct", # TRYBASE Mot 2 torque
ID_dm1 + ":m1s014-Drv01-TrqAct", # TRYBASE Mot 3 torque
ID_dm1 + ":m1s015-Drv01-TrqAct", # TRYBASE Mot 4 torque
ID_dm1 + ":m1s027-Drv01-TrqAct", # TD Mot torque
ID_dm1 + ":m1s011-Drv01-TrqAct", # TRXBASE Mot torque
ID_dm1 + ":m1s030-Drv01-TrqAct", # TRX Mot torque
ID_dm1 + ":m1s031-Drv01-TrqAct", # TRY Mot torque
ID_dm1 + ":m1s029-Drv01-TrqAct", # TRZ Mot torque
ID_dm1 + ":m1s010-Drv01-TrqAct", # ROT2THETA Mot torque
ID_dm1 + ":m1s028-Drv01-TrqAct", # ROTTHETA Mot torque
]
###############################
# Diffractometer 2
ID_dm2 = "SARES32-GPS"
pvs_diffractometer_2 = [
ID_dm2 + ":ROTTHETA-PosAct",
ID_dm2 + ":TRXBASE-PosAct",
ID_dm2 + ":TRY-PosAct",
ID_dm2 + ":TRX-PosAct",
ID_dm2 + ":ROT2THETA-PosAct",
ID_dm2 + ":TRZ-PosAct",
ID_dm2 + ":TD-PosAct",
ID_dm2 + ":ROTX-PosAct",
ID_dm2 + ":ROTZ-PosAct",
ID_dm2 + ":m0s012-Drv01-TrqAct", # TRYBASE Mot 1 torque
ID_dm2 + ":m0s012-Drv01-TrqAct", # TRYBASE Mot 2 torque
ID_dm2 + ":m0s014-Drv01-TrqAct", # TRYBASE Mot 3 torque
ID_dm2 + ":m0s015-Drv01-TrqAct", # TRYBASE Mot 4 torque
ID_dm2 + ":m0s027-Drv01-TrqAct", # TD Mot torque
ID_dm2 + ":m0s011-Drv01-TrqAct", # TRXBASE Mot torque
ID_dm2 + ":m0s030-Drv01-TrqAct", # TRX Mot torque
ID_dm2 + ":m0s032-Drv01-TrqAct", # ROTX Mot torque
ID_dm2 + ":m0s033-Drv01-TrqAct", # ROTZ Mot torque
ID_dm2 + ":m0s010-Drv01-TrqAct", # ROT2THETA Mot torque
ID_dm2 + ":m0s028-Drv01-TrqAct", # ROTTHETA Mot torque
]
###############################
# Huber vertical stage
pvs_huber_z= [
"SARES30-MOBI2:MOT_Z.RBV",
]
###########################################################################
#### CRISTALLINA-MX EXPERIMENT
###############################
# Fast XY-stage
pvs_swissmx = [
"SAR-EXPMX:MOT_FX.RBV",
"SAR-EXPMX:MOT_FY.RBV",
]
###########################################################################
#### CHANNEL GROUPS
###############################
# All channels (slic updates the list based on these)
pv_channels = (
pvs_machine
# + pvs_RF
# + pvs_undulator
+ pvs_gas_monitor
+ pvs_undulator
+ pvs_OAPU044
+ pvs_gas_monitor
+ pvs_PBPS053
+ pvs_OATT053
+ pvs_PPRM053
# + pvs_PDIM053
+ pvs_PSSS059
# + pvs_PPRM064
# + pvs_OOMH064
# + pvs_PPRM066
+ pvs_OOMH067
+ pvs_PSCR068
+ pvs_OOMH084
+ pvs_PPRM085
+ pvs_OAPU107
+ pvs_ODCC110
+ pvs_PSCR110
+ pvs_PBPS113
+ pvs_PDIM113
+ pvs_PPRM113
+ pvs_OLAS147
+ pvs_OAPU149
@ -601,44 +867,81 @@ pv_channels = (
+ pvs_OKBV153
+ pvs_PSCD153
+ pvs_OKBH154
+ pvs_i0_chamber
+ pvs_standa
# + pvs_newport_300
# + pvs_newport_300
# + pvs_smaract_xyz
+ pvs_diffractometer_1
+ pvs_diffractometer_2
+ pvs_huber_z
+ pvs_JJ_slits
# + pvs_swissmx
# + pvs_Bernina
# + pvs_attocube
# + pvs_smaract_juraj
# + pvs_photon_energy_bernina
# + pvs_OAPU092_bernina
# + pvs_OOMV092_bernina
# + pvs_PPRM094_bernina
# + pvs_OOMV096_bernina
# + pvs_PSCR097_bernina
# + pvs_ODCM098_bernina
# + pvs_OAPU102_bernina
# + pvs_PSRD103_bernina
# + pvs_PBPS113_bernina
# + pvs_OPPI113_bernina
# + pvs_PPRM113_bernina
)
# + pvs_attocube
# + pvs_smaract_juraj
pv_channels_front_end = (
pv_channels_cristallina_beamline = (
pvs_machine
# + pvs_RF
# + pvs_undulator
+ pvs_gas_monitor
+ pvs_undulator
+ pvs_OAPU044
+ pvs_gas_monitor
+ pvs_PBPS053
+ pvs_OATT053
+ pvs_PPRM053
# + pvs_PDIM053
+ pvs_PSSS059
# + pvs_PPRM064
# + pvs_OOMH064
# + pvs_PPRM066
+ pvs_OOMH067
+ pvs_PSCR068
+ pvs_OOMH084
+ pvs_PPRM085
+ pvs_OAPU107
+ pvs_ODCC110
+ pvs_PSCR110
+ pvs_PBPS113
+ pvs_PDIM113
+ pvs_PPRM113
+ pvs_OLAS147
+ pvs_OAPU149
+ pvs_PBPS149
+ pvs_PPRM150
+ pvs_OATA150
+ pvs_OPPI151
+ pvs_ODMV152
+ pvs_OKBV153
+ pvs_PSCD153
+ pvs_OKBH154
+ pvs_i0_chamber
)
pv_channels_bernina = (
pv_channels_bernina_DCM = (
pvs_machine
# + pvs_RF
# + pvs_undulator
+ pvs_gas_monitor
+ pvs_undulator
+ pvs_OAPU044
+ pvs_gas_monitor
+ pvs_PBPS053
+ pvs_OATT053
+ pvs_PPRM053
# + pvs_PDIM053
+ pvs_PSSS059
# + pvs_PPRM064
# + pvs_OOMH064
# + pvs_PPRM066
+ pvs_OOMH067
+ pvs_PSCR068
+ pvs_photon_energy_bernina
@ -651,5 +954,6 @@ pv_channels_bernina = (
+ pvs_OAPU102_bernina
+ pvs_PSRD103_bernina
+ pvs_PBPS113_bernina
+ pvs_PPRM113
+ pvs_OPPI113_bernina
+ pvs_PPRM113_bernina
)

54
cristallina.py Normal file → Executable file
View File

@ -78,11 +78,19 @@ from channels.bs_channels import (
from channels.pv_channels import pv_channels
from spreadsheet import overview
from channels.bs_channels import bs_channels_bernina_DCM
from channels.pv_channels import pv_channels_bernina_DCM
from channels.bs_channels import bs_channels_cristallina_beamline
from channels.pv_channels import pv_channels_cristallina_beamline
# from channels_minimal import detectors_min, channels_min, pvs_min
################# DEVICES #################
dummy = DummyAdjustable(units="au")
dummy2 = DummyAdjustable(ID='DUMMY2', name='Dummy2', units="au")
# from devices.knife_edge import KnifeEdge
@ -97,7 +105,8 @@ from beamline.components import (
pulsepicker,
alignment_laser,
pbps113,
pbps149,
mono,
m3,
)
from beamline.components import kbHor, kbVer
@ -107,13 +116,32 @@ from systems.components import cta
from gp_exp.components import Newport_large, OWIS
# Undulators
from beamline import undulator
undulators = undulator.Undulators()
logger.info(f"Using undulator (Aramis) offset to PSSS energy of {undulator.energy_offset} eV.")
# Undulators & mono
from beamline import photon_energy
cr_photon_energy = photon_energy.PhotonEnergy()
logger.info(f"Photon energy offsets: PSSS {photon_energy.energy_offset_PSSS} eV , DCCM {photon_energy.energy_offset_DCCM} eV, undulator {photon_energy.energy_offset_undulators} eV.")
# Pulse picker shutter
#pp_shutter = PP_Shutter(
# "SARES30-LTIM01-EVR0:RearUniv0-Ena-SP", name="Cristallina pulse picker shutter"
#) # Shutter buttton when using the pulse picker
## Slits
from slic.devices.xoptics import slits
@ -129,9 +157,11 @@ BerninaDCM = BerninaMono("SAROP21-ODCM098")
# Diffractometer
from crq_exp.diffractometer import Diffractometer
dm1 = Diffractometer("SARES30-CPCL-ECMC02")
dm2 = Diffractometer("SARES32-GPS")
diffractometer = Diffractometer("diffractometer")
# Set according to which diffractometer is being used
diffractometer = dm1
# Dilution fridge
from crq_exp.dilsc import Dilution
@ -144,7 +174,7 @@ except Exception as e:
# MX adajustables
import mx.mx_adjustables
# import mx.mx_adjustables
################# Stand setup ##################
@ -158,8 +188,8 @@ adjs_for_spreadsheet = {
#"Time": Time(),
"Transmission": attenuator.trans1st,
"Upstream Transmission": upstream_attenuator.trans1st,
"Energy_setpoint": undulators,
"Energy_offset": undulator.energy_offset,
"Energy_setpoint": cr_photon_energy,
"Energy_offset undulator": photon_energy.energy_offset_undulators,
"TD": diffractometer.td,
"TRX": diffractometer.tr_x,
"TRY": diffractometer.tr_y,
@ -176,7 +206,7 @@ if dilution is not None:
"Magnet_Y": dilution.y,
"Magnet_Z": dilution.z,
"DilSc_T_chip": dilution.T_chip,
"DilSc_T_pucksensor": dilution.T_pucksensor,
"DilSc_T_pucksensor": dilution.T_reg,
}
adjs_for_spreadsheet.update(adjs_dilsc)
@ -195,7 +225,6 @@ spreadsheet = Spreadsheet(
try:
from stand.client import Client
stand_host = "saresc-vcons-02.psi.ch"
stand_client = Client(host=stand_host, port=9090)
response = stand_client.get()
@ -209,7 +238,8 @@ except Exception as error:
################# DAQ Setup #################
instrument = "cristallina"
experiment_type = "MX" # "MX" or "Q" for the different setups and detector configurations
# experiment_type = "MX" # "MX" or "Q" for the different setups and detector configurations
experiment_type = "Q" # "MX" or "Q" for the different setups and detector configurations
from pgroups import pgroup, pgroup_scratch
@ -242,6 +272,9 @@ else:
logger.error(f"Experiment type {experiment_type} not supported. Exiting.")
sys.exit(1)
# default_channels=bs_channels,
# default_pvs=pv_channels,
daq.update_config_pvs()
@ -262,7 +295,7 @@ DAQS = multiple_daqs.generate_DAQS(instrument, pgroup, bs_channels, pv_channels,
# required fraction defines ammount of data recorded to save the step and move on to the next one
check_intensity_gas_monitor = PVCondition(
"SARFE10-PBPG050:PHOTON-ENERGY-PER-PULSE-US",
vmin=4,
vmin=400,
vmax=2000,
wait_time=0.5,
required_fraction=0.8,
@ -271,5 +304,6 @@ check_intensity_gas_monitor = PVCondition(
scan = Scanner(default_acquisitions=[daq], condition=check_intensity_gas_monitor)
gui = GUI(scan, show_goto=True, show_spec=True)
logger.info(f"Running at {instrument} with pgroup {pgroup}. Experiment type: {experiment_type}.")
logger.info("Loading finished.")

42
crq_exp/diffractometer.py Normal file → Executable file
View File

@ -16,20 +16,44 @@ from slic.devices.general.motor import Motor
class Diffractometer(Device):
def __init__(self, ID, motor_naming="MOTOR", **kwargs):
def __init__(self, ID, **kwargs):
super().__init__(ID, **kwargs)
self.twotheta = Motor("SARES30-CPCL-ECMC02:ROT2THETA") # , ID=None, name=None, units=None, internal=False):
self.theta = Motor("SARES30-CPCL-ECMC02:ROTTHETA") # , ID=None, name=None, units=None, internal=False):
self.twotheta = Motor(ID + ":ROT2THETA") # , ID=None, name=None, units=None, internal=False):
self.theta = Motor(ID + ":ROTTHETA") # , ID=None, name=None, units=None, internal=False):
self.trx_base = Motor("SARES30-CPCL-ECMC02:TRXBASE") # , ID=None, name=None, units=None, internal=False):
self.try_base = Motor("SARES30-CPCL-ECMC02:TRYBASE") # , ID=None, name=None, units=None, internal=False):
self.trx_base = Motor(ID + ":TRXBASE") # , ID=None, name=None, units=None, internal=False):
self.try_base = Motor(ID + ":TRYBASE") # , ID=None, name=None, units=None, internal=False):
self.tr_x = Motor("SARES30-CPCL-ECMC02:TRX")
self.tr_y = Motor("SARES30-CPCL-ECMC02:TRY")
self.tr_z = Motor("SARES30-CPCL-ECMC02:TRZ")
self.tr_x = Motor(ID + ":TRX")
self.tr_y = Motor(ID + ":TRY")
self.tr_z = Motor(ID + ":TRZ")
self.td = Motor("SARES30-CPCL-ECMC02:TD")
self.td = Motor(ID + ":TD")
if ID == "SARES32-GPS":
self.name = "DM2: Cristallina pulsed magnet diffractometer"
# This diffractometer also has extra swivel stages
self.rotx = Motor(ID + ":ROTX")
self.rotz = Motor(ID + ":ROTZ")
if ID == "SARES30-CPCL-ECMC02":
self.name = "DM1: Cristallina dilution fridge diffractometer"
# class Diffractometer(Device):
# def __init__(self, ID, motor_naming="MOTOR", **kwargs):
# super().__init__(ID, **kwargs)
# self.twotheta = Motor("SARES30-CPCL-ECMC02:ROT2THETA") # , ID=None, name=None, units=None, internal=False):
# self.theta = Motor("SARES30-CPCL-ECMC02:ROTTHETA") # , ID=None, name=None, units=None, internal=False):
# self.trx_base = Motor("SARES30-CPCL-ECMC02:TRXBASE") # , ID=None, name=None, units=None, internal=False):
# self.try_base = Motor("SARES30-CPCL-ECMC02:TRYBASE") # , ID=None, name=None, units=None, internal=False):
# self.tr_x = Motor("SARES30-CPCL-ECMC02:TRX")
# self.tr_y = Motor("SARES30-CPCL-ECMC02:TRY")
# self.tr_z = Motor("SARES30-CPCL-ECMC02:TRZ")
# self.td = Motor("SARES30-CPCL-ECMC02:TD")
# Set speed:

73
crq_exp/dilsc.py Normal file → Executable file
View File

@ -25,11 +25,9 @@ class Dilution(Device):
self.x = MagnetCoil("X", self.dilsc, 'x', limit_low=-0.6, limit_high=0.6)
self.y = MagnetCoil("Y", self.dilsc, 'y', limit_low=-0.6, limit_high=0.6)
self.z = MagnetCoil("Z", self.dilsc, 'z', limit_low=-5.2, limit_high=5.2)
# not in use currently
# self.T_plato = Thermometer('T_plato', self.dilsc, limit_low=0, limit_high=300)
self.T_plato = Thermometer('T_plato', self.dilsc, limit_low=0, limit_high=300)
self.T_chip = Thermometer('T_chip', self.dilsc, limit_low=0, limit_high=300)
self.T_pucksensor = Thermometer('T_pucksensor', self.dilsc, limit_low=0, limit_high=300)
self.T_reg = Thermometer('T_reg', self.dilsc, limit_low=0, limit_high=300)
class Thermometer(Adjustable):
@ -37,7 +35,18 @@ class Thermometer(Adjustable):
super().__init__(name, limit_low=limit_low, limit_high=limit_high)
self.dilsc = dilsc_connection
# Heater to regulate channel A on the Galgen LakeShore372. Give value in Ohm.
self.heater_resistance = 82
# Defines heater ranges and PID values for various control temperature regions.
self.heater_settings = [
{'range': 'off', 'pid': (800, 1, 0), 'temp_start': -1, 'temp_end': 0.00099},
{'range': '300uA', 'pid': (800, 1, 0), 'temp_start': 0.001, 'temp_end': 0.037},
{'range': '1mA', 'pid': (40, 14, 0), 'temp_start': 0.038, 'temp_end': 0.108},
{'range': '3mA', 'pid': (4, 15, 0), 'temp_start': 0.110, 'temp_end': 0.350},
{'range': '10mA', 'pid': (2, 12, 0), 'temp_start': 0.352, 'temp_end': 1.100},
{'range': '30mA', 'pid': (2, 60, 0), 'temp_start': 1.100, 'temp_end': 2.300}
]
def _check_connection(func):
def checker(self, *args, **kwargs):
@ -47,6 +56,26 @@ class Thermometer(Adjustable):
return func(self, *args, **kwargs)
return checker
@_check_connection
def set_heater_range(self, range_value):
""" Sets the heater range for the control channel and sets the PID parameters for the associated control loop.
TODO: Consider redoing so that it only works for the T_reg channel.
TODO: the pid values are now sent with stringio and not saved as parameters in slic, this should be fixed.
-
"""
heater_range_map = {
'off': 0, '30uA': 1, '100uA': 2, '300uA': 3, '1mA': 4, '3mA': 5, '10mA': 6, '30mA': 7, '100mA': 8}
if range_value not in heater_range_map:
raise ValueError("Invalid range value. Allowed are: ['off','30uA','100uA','300uA','1mA','3mA','10mA','30mA','100mA']")
enum_value = heater_range_map[range_value]
self.dilsc.setParameter(self.name, 'htrrng', enum_value)
for setting in self.heater_settings:
if setting['range'] == range_value:
self.set_PID_parameters(*setting['pid'])
break
return
@_check_connection
def get_current_value(self):
cacheitem = self.dilsc.getParameter(f'{self.name}', 'value', trycache=False)
@ -54,7 +83,16 @@ class Thermometer(Adjustable):
@_check_connection
def set_target_value(self, value):
def set_target_value(self, value, adjust_heater_range=True):
if adjust_heater_range:
range_to_set = None
for setting in self.heater_settings:
if setting['temp_start'] <= value and setting['temp_end'] >= value:
range_to_set = setting['range']
if range_to_set != None:
self.set_heater_range(range_to_set)
else:
raise ValueError(f"Heater range for the target value {value} could not be set")
self.dilsc.setParameter(f'{self.name}', 'target', value)
@_check_connection
@ -73,7 +111,8 @@ class Thermometer(Adjustable):
""" Returns the current PID parameters associated with the control loop for
this thermometer.
"""
response = self.dilsc.getParameter(f'{self.name}','ctrlpars', trycache=False)
# response = self.dilsc.getParameter(f'{self.name}','ctrlpars', trycache=False)
response = self.dilsc.execCommand('lscio', 'communicate', 'PID?')
return response
@_check_connection
@ -84,8 +123,10 @@ class Thermometer(Adjustable):
- The range is limited to less than the Lakeshore range allows, this needs
to be fixed in frappy.
"""
self.dilsc.setParameter(f'{self.name}', 'ctrlpars', {'p': p, 'i': i, 'd': d})
# self.dilsc.setParameter(f'{self.name}', 'ctrlpars', {'p': p, 'i': i, 'd': d})
command_string = f'PID {0},{p},{i},{d}; PID?'
self.dilsc.execCommand('lscio', 'communicate', command_string)
class MagnetCoil(Adjustable):
@ -123,5 +164,19 @@ class MagnetCoil(Adjustable):
def is_moving(self):
response = self.dilsc.getParameter(f'mf{self.direction}','status', trycache=False)
return response[0][0] > StatusType.PREPARED
@_check_connection
def set_ramp_speed(self, direction, value):
""" Sets ramp speed for a given direction (x,y or z) and value in T/min.
"""
if value > 0.5:
raise ValueError('Do not exceed 0.5 T/min unless you want a quench party')
if value <= 0:
raise ValueError('Only positive values are allowed')
if self.direction not in ["x", "y", "z"]:
raise ValueError("Direction must be either x, y or z.")
else:
self.dilsc.setParameter(direction, 'ramp', value)
return

0
crq_exp/synchronization.py Normal file → Executable file
View File

0
devices/knife_edge.py Normal file → Executable file
View File

0
environment.txt Normal file → Executable file
View File

5
exp_temp/I0_foil_motor.py Executable file
View File

@ -0,0 +1,5 @@
from slic.devices.general.motor import Motor
from slic.devices.general.smaract import SmarActAxis
I0_foils = Motor("SARES30-MCS20610:MCS3")
# I0_foils = SmarActAxis("SARES30-MCS20610:MCS3")

184
exp_temp/fake_attenuator.py Executable file
View File

@ -0,0 +1,184 @@
from time import sleep
from slic.core.adjustable import Adjustable, PVAdjustable
from slic.core.device import Device, SimpleDevice
from slic.devices.general.motor import Motor
from slic.utils.hastyepics import get_pv as PV
class Attenuator(Device):
def __init__(self, ID, energy_threshold=1500, name="Attenuator Aramis", process_time=1, **kwargs):
super().__init__(ID, name=name, **kwargs)
# self.motor_limits = motor_limits
# self.motors = motors = LimitedMotors(ID, motor_limits)
self.motor_status_pvs = [PVAdjustable(f"{ID}:MOTOR_{i}.DMOV") for i in [1,2,3,4,5,6]]
# self.motors = LimitedMotors(ID, motor_limits)
self.trans1st = Transmission(ID, process_time=process_time)
self.trans3rd = Transmission(ID, process_time=process_time, third_order=True)
self.energy = LimitedEnergy(ID, energy_threshold, process_time)
self.foils = [Foil(ID, i+1) for i in range(6)]
def get_current_transmission(self):
return self.trans1st.get_current_value()
def get_current_transmission_third_harmonic(self):
return self.trans3rd.get_current_value()
def set_transmission(self, value, energy=None):
self.energy.set_target_value(energy)
self.trans1st.set_target_value(value)
def set_transmission_third_harmonic(self, value, energy=None):
self.energy.set_target_value(energy)
self.trans3rd.set_target_value(value)
def set_foils_combination(self, combination: list, wait=False):
assert len(combination) == 6, "Invalid combination entered"
for value in combination:
assert value in self.foils[0].values, "wrong value entered"
for i, (foil,value) in enumerate(zip(self.foils,combination)):
print(f"setting {repr(foil)} to position {value}")
foil.set_target_value(value)
if wait:
self.foils[0].wait_for_motion()
class Transmission(PVAdjustable):
def __init__(self, ID, third_order=False, check_motors=True, **kwargs):
#self.motors = motors
self.third_order = third_order
self.motors = [Motor(f"{ID}:MOTOR_{i}") for i in [1,2,3,4,5,6]]
self.check_motors = check_motors
prefix = ID + ":"
# Changed for new attenuator IOC
pvname_setvalue = prefix + "UsrRec.TD"
pvname_readback = prefix + ("UsrRec.TC3" if third_order else "UsrRec.TC1")
super().__init__(pvname_setvalue, pvname_readback, **kwargs)
self.pvnames.third_order_toggle = pvn = prefix + "UsrRec.HRM3"
self.pvs.third_order_toggle = PV(pvn)
pv_calculated = prefix + ("UsrRec.TR3" if third_order else "UsrRec.TR1")
pv_current = prefix + ("UsrRec.TC3" if third_order else "UsrRec.TC1")
self.calculated_trans = PVAdjustable(pv_calculated).get_current_value()
self.current_trans = PVAdjustable(pv_current).get_current_value()
def set_target_value(self, *args, **kwargs):
self.set_third_order_toggle()
t = super().set_target_value(*args, **kwargs)
self.wait_for_motion()
return t
def set_third_order_toggle(self):
self.pvs.third_order_toggle.put(self.third_order)
def wait_for_motion(self):
sleep(1) # to be certain that motion has started
while True:
if not self.is_moving():
break # motion is completed
sleep(0.25)
def is_moving(self):
if self.check_motors:
return any(m.is_moving() for m in self.motors)
else:
return (self.calculated_trans != self.current_trans)
class LimitedEnergy(PVAdjustable):
def __init__(self, ID, threshold, wait_time):
self.threshold = threshold
self.wait_time = wait_time
super().__init__(ID + ":UsrRec.ERY")
prefix = ID + ":"
self.pvnames.fel_energy = pvn = prefix + "ENY_CALC" # uses the new calculated energy from attenuator IOC
self.pvs.fel_energy = PV(pvn)
def set_target_value(self, value):
threshold = self.threshold
wait_time = self.wait_time
while not value:
value = self.pvs.fel_energy.get()
if value is not None:
if value >= threshold:
break
print(f"Machine photon energy ({value} eV) is below {threshold} eV - waiting for the machine to recover...")
value = None
sleep(wait_time)
super().set_target_value(value) # setting the energy is now instantanious, motors will still move afterwards.
print(f"Set attenuator energy to {value} eV")
class Foil(PVAdjustable):
def __init__(self, ID, number,check_motors=True):
""" Foil with possible settings of 0,1,2,3 or 4.
"""
assert 0 <= int(number) <= 6, "Invalid foil selected"
super().__init__(ID + f":UsrRec.FI{number}")
self.values = [0, 1, 2, 3, 4]
prefix = ID + ":"
self.motors = [Motor(f"{ID}:MOTOR_{i}") for i in [1,2,3,4,5,6]]
self.check_motors = check_motors
pv_calculated = prefix + "UsrRec.TR1"
pv_current = prefix + "UsrRec.TC1"
self.calculated_trans = PVAdjustable(pv_calculated).get_current_value()
self.current_trans = PVAdjustable(pv_current).get_current_value()
def set_target_value(self, *args, **kwargs):
t = super().set_target_value(*args, **kwargs).wait()
self.wait_for_motion()
return t
def wait_for_motion(self):
sleep(1) # to be certain that motion has started
while True:
if not self.is_moving():
break # motion is completed
sleep(0.25)
def is_moving(self):
if self.check_motors:
return any(m.is_moving() for m in self.motors)
else:
return (self.calculated_trans != self.current_trans)

0
exp_temp/mono.py Normal file → Executable file
View File

6
experiments/DilSC/TwoTheta_scan.ipynb Normal file → Executable file
View File

@ -193,9 +193,9 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python [conda env:conda-slic]",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "conda-env-conda-slic-py"
"name": "python3"
},
"language_info": {
"codemirror_mode": {
@ -207,7 +207,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.18"
"version": "3.9.20"
}
},
"nbformat": 4,

12
experiments/PMS/PMS.py Normal file → Executable file
View File

@ -32,3 +32,15 @@ class PP_Shutter:
def __repr__(self):
tn = typename(self)
return f'{tn} "{self.name}" is {self.status}'
def get_Cernox_temperature():
""" Very improvised """
import csv
fname = '/gfa/.mounts/sf_cristallina/applications/devices/CryovacTIC/temperatures_009.csv'
with open(fname) as f:
reader = csv.reader(f)
rows = [row for row in reader]
return float(rows[-1][3])

0
gp_exp/attocube.py Normal file → Executable file
View File

0
gp_exp/attocube_device_def.py Normal file → Executable file
View File

0
gp_exp/components.py Normal file → Executable file
View File

0
gp_exp/jj_device_def.py Normal file → Executable file
View File

0
gp_exp/newport.py Normal file → Executable file
View File

0
gp_exp/smaract.py Normal file → Executable file
View File

0
gp_exp/smaract_device_def.py Normal file → Executable file
View File

0
gp_exp/standa.py Normal file → Executable file
View File

0
log/cristallina.log Normal file → Executable file
View File

File diff suppressed because one or more lines are too long

Binary file not shown.

0
measurement_scripts/DilSc_commisioning_pulses.py Normal file → Executable file
View File

0
measurement_scripts/DilSc_frappy_client.py Normal file → Executable file
View File

0
measurement_scripts/DilSc_meander_scripts.py Normal file → Executable file
View File

6
measurement_scripts/Untitled.ipynb Normal file → Executable file
View File

@ -30,9 +30,7 @@
"cell_type": "code",
"execution_count": 7,
"id": "d108c981",
"metadata": {
"scrolled": false
},
"metadata": {},
"outputs": [
{
"data": {
@ -1166,7 +1164,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.13"
"version": "3.9.20"
}
},
"nbformat": 4,

View File

View File

0
measurement_scripts/hole_drilling.py Normal file → Executable file
View File

0
measurement_scripts/inprints.py Normal file → Executable file
View File

0
measurement_scripts/move_newport.py Normal file → Executable file
View File

0
mx/knife_edge_prototype.py Normal file → Executable file
View File

23
mx/mx_adjustables.py Normal file → Executable file
View File

@ -1,22 +1,27 @@
from slic.core.device.simpledevice import SimpleDevice
from slic.devices.general.motor import Motor
# hve positioners
hve_mot_v = Motor("SARES30-MOBI1:MOT_1")
hve_mot_h1 = Motor("SARES30-MOBI1:MOT_2")
hve_mot_h2 = Motor("SARES30-MOBI1:MOT_3")
# collimator
mx_coll_x = Motor("SARES30-SMX:MCS1")
mx_coll_y = Motor("SARES30-SMX:MCS2")
coll_x = Motor("SARES30-SMX:MCS1")
coll_y = Motor("SARES30-SMX:MCS2")
# post-tube
mx_pt_x1 = Motor("SARES30-SMX:MCS4")
mx_pt_x2 = Motor("SARES30-SMX:MCS5")
mx_pt_y1 = Motor("SARES30-SMX:MCS6")
mx_pt_y2 = Motor("SARES30-SMX:MCS7")
mx_pt_z = Motor("SARES30-SMX:MCS8")
pt_x1 = Motor("SARES30-SMX:MCS4")
pt_x2 = Motor("SARES30-SMX:MCS5")
pt_y1 = Motor("SARES30-SMX:MCS6")
pt_y2 = Motor("SARES30-SMX:MCS7")
pt_z = Motor("SARES30-SMX:MCS8")
# post-tube
mx_detector_z = Motor("SAR-EXPMX:MOT_DET_Z")
detector_z = Motor("SAR-EXPMX:MOT_DET_Z")
# post-tube
mx_backlight = Motor("SAR-EXPMX:MOT_BLGT")
backlight = Motor("SAR-EXPMX:MOT_BLGT")
# fast stage
mx_fast_x = Motor("SAR-EXPMX:MOT_FX")

205
mx/mx_experiment.py Normal file → Executable file
View File

@ -1,19 +1,104 @@
# Moved from main cristallina.py here temporarily
mxdaq = SFAcquisition(
instrument,
pgroup,
default_channels=bs_channels,
default_pvs=pvs,
default_detectors=detectors_MX,
rate_multiplicator=1,
append_user_tag_to_data_dir=True
#!/usr/bin/env python
import sys
import os
from loguru import logger
# at the moment this allows us to group the subdirectories as modules easily
# TODO: a more general way would be to have this cristallina as a installed package
sys.path.insert(0, os.path.expanduser("/sf/cristallina/applications/slic/cristallina"))
def setup_general_logging():
"""Setup logging to console and files in both the snapshots and
the respective pgroup.
"""
logger.remove()
logger.add(
sys.stderr,
format="{time:YYYY-MM-DD at HH:mm:ss} | {level} | {message}",
level="INFO",
)
logger.info("Loading started.")
# create file handler which logs
try:
logger.add(
"/sf/cristallina/applications/beamline/snapshots/slic_logs/cristallina_mx.log",
format="{time:YYYY-MM-DD at HH:mm:ss} | {level} | {message}",
level="DEBUG",
rotation="1 week",
)
logger.info("Logging to snapshots.")
except PermissionError as e:
logger.warning("Cannot write log file to snapshots.")
logger.warning(e)
def setup_logging_pgroup(pgroup, level="INFO"):
try:
logger.add(
f"/sf/cristallina/data/{pgroup}/scratch/slic.log",
format="{time:YYYY-MM-DD at HH:mm:ss} | {level} | {message}",
level=level,
rotation="1 week",
)
logger.info(f"Logging to pgroup {pgroup}.")
except PermissionError as e:
logger.warning(f"Cannot write log file to pgroup {pgroup}.")
# We setup the logging before going further so that
# other modules can write startup messages into the log file.
setup_general_logging()
from slic.gui import GUI
from slic.core.adjustable import Adjustable, PVAdjustable, DummyAdjustable
from slic.core.acquisition import SFAcquisition, PVAcquisition
from slic.core.condition import PVCondition
from slic.core.scanner import Scanner
from slic.devices.general.motor import Motor
from slic.utils import devices, Marker, as_shortcut, snapshot
from slic.utils import Channels, Config, Elog, Screenshot, PV
from slic.core.acquisition.fakeacquisition import FakeAcquisition
print( os.getcwd() )
from channels.bs_channels import (
detectors_MX,
bs_channels,
camera_channels,
)
mxscan = Scanner(default_acquisitions=[mxdaq], condition=check_intensity_gas_monitor)
from channels.pv_channels import pv_channels
mxgui = GUI(mxscan, show_goto=True, show_spec=False, show_scan=False, show_scan2D=False, show_run=False, show_static=False, show_sfx=True, start_tab="sfx")
############## MX motors ##############
################# DEVICES #################
dummy = DummyAdjustable(units="au")
from devices.knife_edge import KnifeEdge
# from devices.standa import standa
# from devices.newport import newport
from beamline.components import (
upstream_attenuator,
attenuator,
pp_shutter,
pulsepicker,
alignment_laser,
pbps113,
pbps149,
)
from systems.components import cta
# MX adajustables
from slic.core.device.simpledevice import SimpleDevice
from slic.devices.general.motor import Motor
# hve positioners
hve_mot_v = Motor("SARES30-MOBI1:MOT_1")
hve_mot_h1 = Motor("SARES30-MOBI1:MOT_2")
@ -36,18 +121,71 @@ detector_z = Motor("SAR-EXPMX:MOT_DET_Z")
# post-tube
backlight = Motor("SAR-EXPMX:MOT_BLGT")
# fast stage
mx_fast_x = Motor("SAR-EXPMX:MOT_FX")
mx_fast_y = Motor("SAR-EXPMX:MOT_FY")
################# DAQ Setup #################
instrument = "cristallina"
#pgroup = "p21734"
pgroup = "p22215"
# setup pgroup specific logger
setup_logging_pgroup(pgroup)
# Moved from main cristallina.py here temporarily
mxdaq = SFAcquisition(
instrument,
pgroup,
default_channels=bs_channels,
default_pvs=pv_channels,
default_detectors=detectors_MX,
rate_multiplicator=1,
append_user_tag_to_data_dir=True
)
# There is a new EPICS buffer, so the archiver is no longer used. This makes sure we are taking PVs from the right place.
try:
mxdaq.update_config_pvs()
except Exception as e:
logger.warning(f"error updating config pvs for mxdaq: {e}")
check_intensity_gas_monitor = PVCondition(
"SARFE10-PBPG050:PHOTON-ENERGY-PER-PULSE-US",
vmin=4,
vmax=2000,
wait_time=0.5,
required_fraction=0.8,
)
mxscan = Scanner(default_acquisitions=[mxdaq], condition=check_intensity_gas_monitor)
mxgui = GUI(mxscan, show_goto=True, show_spec=False, show_scan=True, show_scan2D=False, show_run=False, show_static=False, show_sfx=True, start_tab="sfx")
#############################################
################# DAQ Setup #################
############## in positions ##############
coll_in_pos_x, coll_in_pos_y = 9.51, -5.62
coll_in_pos_x, coll_in_pos_y = 9.50, 1.38
backlight_in = -30000
detector_in_pos = 1
pt_in_pos_x1, pt_in_pos_x2, pt_in_pos_y1, pt_in_pos_y2, pt_in_pos_z = -3.039, -2.637, 8.904, 13.857, 0
detector_in_pos = 116
pt_in_pos_x1 = -4.301
pt_in_pos_x2 = -4.501
pt_in_pos_y1 = 10.996
pt_in_pos_y2 = 10.664
pt_in_pos_z = 0.5
############## out positions ##############
coll_out_pos_x, coll_out_pos_y = -14.5, 1.32
############## out positions ##############
coll_out_pos_x, coll_out_pos_y = -12, 1.38
backlight_out = 1000
detector_out_pos = 180
pt_out_pos_x1, pt_out_pos_x2, pt_out_pos_y1, pt_out_pos_y2, pt_out_pos_z = 5.960, 6.361, -15.096, -10.143, -8
detector_out_pos = 220
pt_out_pos_x1 = 4.8
pt_out_pos_x2 = 4.6
pt_out_pos_y1 = -12.8
pt_out_pos_y2 = -13.1
pt_out_pos_z = -8
@as_shortcut
def a_data_collection():
@ -56,52 +194,61 @@ def a_data_collection():
backlight.set( backlight_out ).wait()
# post-tube in
pt_x1_in = pt_x1.set( pt_in_pos_x1 ) # this runs in parallel
pt_x2_in = pt_x2.set( pt_in_pos_x2 ) # this runs in parallel
pt_y1_in = pt_y1.set( pt_in_pos_y1 ) # this runs in parallel
pt_y2_in = pt_y2.set( pt_in_pos_y2 ) # this runs in parallel
pt_z_in = pt_z.set( pt_in_pos_z ) # this runs in parallel
for t in (pt_x1_in, pt_x2_in, pt_y1_in, pt_y2_in, pt_z_in): # this waits for all of them to be done!
for t in (pt_x1_in, pt_x2_in, pt_y1_in, pt_y2_in): # this waits for all of them to be done!
logger.info(f"waiting for post-tube to move in")
t.wait()
pt_z_in = pt_z.set( pt_in_pos_z ).wait() # this no longer runs in parallel
# collimator in
cx_in = coll_x.set( coll_in_pos_x ) # this runs in parallel
cy_in = coll_y.set( coll_in_pos_y ) # this runs in parallel
for t in (cx_in, cy_in): # this waits for all of them to be done!
logger.info(f"waiting for collimator to move in")
t.wait()
# detector in
logger.info(f"waiting for detector to move in")
detector_z.set( detector_in_pos ).wait() # this runs in parallel
@as_shortcut
def b_sample_alignment():
# detector out
logger.info(f"waiting for detector to move out")
detector_z.set( detector_out_pos ).wait()
# collimator out
cx_out = coll_x.set( coll_out_pos_x ) # this runs in parallel
cy_out = coll_y.set( coll_out_pos_y ) # this runs in parallel
for t in (cx_out, cy_out): # this waits for all of them to be done!
logger.info(f"waiting for collimator to move out")
t.wait()
# post-tube out
pt_z_out = pt_z.set( pt_out_pos_z ).wait() # this runs in parallel
pt_x1_out = pt_x1.set( pt_out_pos_x1 ) # this runs in parallel
pt_x2_out = pt_x2.set( pt_out_pos_x2 ) # this runs in parallel
pt_y1_out = pt_y1.set( pt_out_pos_y1 ) # this runs in parallel
pt_y2_out = pt_y2.set( pt_out_pos_y2 ) # this runs in parallel
pt_z_out = pt_z.set( pt_out_pos_z ) # this runs in parallel
for t in (pt_x1_out, pt_x2_out, pt_y1_out, pt_y2_out, pt_z_out): # this waits for all of them to be done!
logger.info(f"waiting for post_tube to move out")
t.wait()
@as_shortcut
def c_backlight_in():
# safety logic for backlight in
if coll_x.get() < 0 and pt_y1.get() < 0 and detector_z.get() > 20:
if round( coll_x.get(), 2 ) == coll_out_pos_x and round( pt_y1.get(), 2 ) == pt_out_pos_y1 and round( detector_z.get(), 2 ) > detector_in_pos:
backlight.set( backlight_in ).wait()
else:
print( "devises are in the way" )
logger.warning( "some devices are in the way" )
@as_shortcut
def ca_backlight_out():
@ -120,7 +267,7 @@ def post_tube_in():
for t in (pt_x1_in, pt_x2_in, pt_y1_in, pt_y2_in, pt_z_in): # this waits for all of them to be done!
t.wait()
else:
print( "devises are in the way" )
logger.warning( "devices are in the way" )
@as_shortcut
def post_tube_out():
@ -135,13 +282,14 @@ def post_tube_out():
for t in (pt_x1_out, pt_x2_out, pt_y1_out, pt_y2_out, pt_z_out): # this waits for all of them to be done!
t.wait()
else:
print( "detector needs to move" )
logger.warning( "detector needs to move" )
@as_shortcut
def coll_in():
cx_in = coll_x.set( coll_in_pos_x ) # this runs in parallel
cy_in = coll_y.set( coll_in_pos_y ) # this runs in parallel
for t in (cx_in, cy_in): # this waits for all of them to be done!
logger.info(f"waiting for collimator to move in")
t.wait()
@as_shortcut
@ -149,6 +297,7 @@ def coll_out():
cx_out = coll_x.set( coll_out_pos_x ) # this runs in parallel
cy_out = coll_y.set( coll_out_pos_y ) # this runs in parallel
for t in (cx_out, cy_out): # this waits for all of them to be done!
logger.info(f"waiting for collimator to move out")
t.wait()
@as_shortcut
@ -156,12 +305,14 @@ def detector_in():
# safety logic for detector in
if backlight.get() > 0 and pt_y1.get() > 8:
logger.info(f"waiting for detector to move in")
detector_z.set( detector_in_pos ).wait() # this runs in parallel
else:
print( "devises are in the way" )
logger.warning( "devices are in the way" )
@as_shortcut
def detector_out():
logger.info(f"waiting for detector to move out")
detector_z.set( detector_out_pos ).wait() # this runs in parallel

8
pgroups.py Normal file → Executable file
View File

@ -39,5 +39,11 @@ pgroup_scratch = "p19150" # Scratch
# pgroup = "p21977" # CrQ - Dilsc - LiErF4
# pgroup = "p21981" # CrMX JFJ commissioning and other related detector bullocks
pgroup = "p22198" # CrMX Fromme - 2024-10-25
# pgroup = "p22198" # CrMX Fromme - 2024-10-25
# pgroup = "p22214" # CrQ in-house DilSc 2024-11-15
# pgroup = "p22199" # CrQ commissioning PuMa 2024-11-22
pgroup = "p22259" # Cr-Bl commissioning Jan 2025
# pgroup = "p22226" # CrMX user Nogly 2025-02-21

0
scratch/acquisition_setup.py Normal file → Executable file
View File

0
spreadsheet.py Normal file → Executable file
View File

0
stand/client.py Normal file → Executable file
View File

0
stand/time.py Normal file → Executable file
View File

0
systems/README.md Normal file → Executable file
View File

0
systems/components.py Normal file → Executable file
View File

0
templates/cool_motor.py Normal file → Executable file
View File