diff --git a/.furka.py.swo b/.furka.py.swo new file mode 100644 index 0000000..f70213c Binary files /dev/null and b/.furka.py.swo differ diff --git a/constraints.py b/constraints.py new file mode 100644 index 0000000..2346099 --- /dev/null +++ b/constraints.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 + +from math import inf + + +class ExtraConstraint: + + def __init__(self, **kwargs): + self.kwargs = _unpack(kwargs) + + def __call__(self, x): + kwargs = self.kwargs + for name, value in x.items(): + vmin = kwargs.get(f"{name}_min", -inf) + vmax = kwargs.get(f"{name}_max", +inf) + check = (vmin <= value < vmax) +# print(name, f"\t{vmin} <= {value} < {vmax}\t->", check) + if not check: + return False + return True + + + +def _unpack(d): + res = {} + for k, v in d.items(): + if k.endswith("_min") or k.endswith("_max"): + res[k] = v + else: + try: + vmin, vmax = v + except (ValueError, TypeError) as e: + raise ValueError(f"cannot unpack {k} = {v} into ({k}_min, {k}_max), need exactly 2 values") from e + res[k + "_min"] = vmin + res[k + "_max"] = vmax + if res != d: + print(f"unpacked: {d} -> {res}") + return res + + + +if __name__ == "__main__": + + cons = ExtraConstraint(beta_min=0, beta_max=10, gamma_max=33) + + + example = { + "alpha": 1, + "beta": 1 + } + + assert cons(example) + + + example = { + "alpha": 1, + "beta": 11 + } + + assert not cons(example) + + + example = { + "gamma": 3 + } + + assert cons(example) + + + example = { + "gamma": 333 + } + + assert not cons(example) + + + cons = ExtraConstraint(alpha=(1, 100)) + + example = { + "alpha": 10 + } + + assert cons(example) + + example = { + "alpha": 1000 + } + + assert not cons(example) + + + badcons = ExtraConstraint(test=33) + + + diff --git a/furka.py b/furka.py index f412772..b2b56e1 100644 --- a/furka.py +++ b/furka.py @@ -18,34 +18,42 @@ from undulator import Undulators from undulator import Mono from undulator import Coupled_MonoUnd + +from tth import Coupled_tth +from tth import LakeShore + from qspace import QSpace3D from qspace import Wavelength from qspace import HistoryDummy +from constraints import ExtraConstraint dummy = DummyAdjustable(units="au") -mot_x = Motor("SATES30-RETRO:MOT_X", name="Retro X") +#mot_x = Motor("SATES30-RETRO:MOT_X", name="Retro X") 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") +#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) +#retro = SimpleDevice("Retro Stages", x=mot_x, y=mot_y, z=mot_z, theta=mot_theta) KBV_RX = PVAdjustable("SATOP31-OKBV178:W_RX.VAL", pvname_moving="SATOP31-OKBV178:MOVING", name = "KB_Vertical_RX") #KBV_RX = PVAdjustable("SATOP31-OKBV178:W_RX.VAL", process_time=1, name = "KBV_RX") KBH_RY = PVAdjustable("SATOP31-OKBH179:W_RY.VAL", pvname_moving="SATOP31-OKBH179:MOVING", name = "KB_Horiz_RY") #KBH_RY = PVAdjustable("SATOP31-OKBH179:W_RY.VAL", process_time=1, name = "KBH_RY") +lxt = PVAdjustable("SLAAT01-LTIM-PDLY:DELAY", pvname_done_moving="SLAAT01-LTIM-PDLY:WAITING", name="LXT") + + #mono_slits = PVAdjustable("SATOP11-OSGM087:EXITSLIT",pvname_done_moving="SATOP31-OEXS132:MOT_H.DMOV", name = "Mono_Slits" ) -n_und_ref = 12 +n_und_ref = 13 n_unds = [ 6, 7, 8, 9, 10, 11, 12, 13, # 14 is the CHIC 15, 16, 17, 18, 19, 20, 21, 22 ] chic_fudge_offset = 0 -Mon2Unds_offset = -5 +Mon2Unds_offset = 9 und = Undulators(n_unds, n_und_ref, chic_fudge_offset, name="z Athos Undulators") #und = Undulators(name="Undulators") @@ -61,15 +69,39 @@ MonUnd = Coupled_MonoUnd( name="Mono+Und" ) +tth_scan = Coupled_tth(delta=0.3885, name="theta 2theta") + +lakeshore = PVAdjustable("SATES30-LS336:LOOP1_SP", "SATES30-LS336:A_RBV", accuracy=0.25, name="Lakeshore Temp") + + + + +#lakeshore = LakeShore(name="Temperature") wl = Wavelength(Mon) + + + mu = Motor("SATES30-RIXS:MOT_SRY.VAL") chi = Motor("SATES30-RIXS:MOT_SRZ.VAL") phi = Motor("SATES30-RIXS:MOT_SRX.VAL") nu = Motor("SATES30-RIXS:MOT_DRY.VAL") q = QSpace3D("SOMETHING:Q", mu, chi, phi, nu, wl) +TX = Motor("SATES30-RIXS:MOT_STX.VAL") +TY = Motor("SATES30-RIXS:MOT_STY.VAL") +TZ = Motor("SATES30-RIXS:MOT_STZ.VAL") +TwoTRY=Motor("SATES30-RIXS:MOT_2TRY.VAL") + + + +PICO_X1 = PVAdjustable("SLAAT31-LMNP-PICO11:DRIVE", name="PICO X1") +PICO_Y1 = PVAdjustable("SLAAT31-LMNP-PICO12:DRIVE", name="PICO Y1") + + + + fake_mu = HistoryDummy.init_from(mu) fake_chi = HistoryDummy.init_from(chi) fake_phi = HistoryDummy.init_from(phi) @@ -77,13 +109,7 @@ fake_nu = HistoryDummy.init_from(nu) fake_q = QSpace3D("FAKE:Q", fake_mu, fake_chi, fake_phi, fake_nu, wl) #fake_q.set_lattice("FAKE:Q", fake_mu, fake_chi, fake_phi, fake_nu, wl) -fake_q.set_lattice("Y-hex", a=5.9, c=43.3) -fake_q.add_orientation((1,0,16), (0,0,1), None, "normal direction") -fake_q.add_orientation((-2,0,1), (0,1,0), None, "beam direction") -fake_q.calc_ub() - - -laser_delay = DelayStage("SLAAT31-LMOT-M808:MOT", name="Laser Delay") +laser_delay = Motor("SLAAT31-LMOT-M808:MOT", name="Laser Delay") laser_WP = Motor("SLAAT31-LMOT-M801:MOT", name="Laser WavePlate") channels = [ @@ -93,15 +119,33 @@ channels = [ "SATES30-LSCP10-FNS:CH0:VAL_GET", "SATES30-LSCP10-FNS:CH1:VAL_GET", "SATES30-LSCP10-FNS:CH2:VAL_GET", + "SATES30-LSCP10-FNS:CH3:VAL_GET", "SATES30-LSCP10-FNS:CH4:VAL_GET", +# "SATOP31-PMOS132-2D:SPECTRUM_CENTER", +# "SATOP31-PMOS132-2D:SPECTRUM_FWHM", +# "SATOP31-PMOS132-2D:SPECTRUM_X", +# "SATOP31-PMOS132-2D:SPECTRUM_Y", +# "SATOP31-PMOS132-2D:processing_parameters", +# "SATES30-CVME-EVR0:CALCS", + "SLAAT21-LSCP01-FNS:CH0:VAL_GET", + "SLAAT21-LSCP01:CH0:1", # "SATES30-LSCP10-FNS:CH0:WFMi" # "SATES31-CAMS187-RIXS1:SPC", # "SATES31-CAMS187-RIXS1:SPC_gauss", # "SATES31-CAMS187-RIXS1:SPC_wgt", - "SATES31-CAMS187-RIXS1:Spectrum", +# "SATES31-CAMS187-RIXS1:Spectrum", # "SATES31-CAMS187-RIXS1:evt_list", - "SATES31-CAMS187-RIXS1:FPICTURE" - +# "SATES31-CAMS187-RIXS1:FPICTURE" + "SATES30-CVME-EVR0:DUMMY_PV1_NBS", + "SATES30-CVME-EVR0:DUMMY_PV2_NBS", + "SATES30-CVME-EVR0:DUMMY_PV3_NBS", + "SATES30-CVME-EVR0:DUMMY_PV4_NBS", + "SATES30-CVME-EVR0:DUMMY_PV5_NBS", + "SATES30-CVME-EVR0:DUMMY_PV6_NBS", + "SATES30-CVME-EVR0:DUMMY_PV7_NBS", + "SATES30-CVME-EVR0:DUMMY_PV8_NBS", + "SATES30-CVME-EVR0:DUMMY_PV9_NBS", + "SATES30-CVME-EVR0:DUMMY_PV10_NBS" ] pvs = [ diff --git a/nightscan_4.py b/nightscan_4.py new file mode 100644 index 0000000..829676d --- /dev/null +++ b/nightscan_4.py @@ -0,0 +1,71 @@ +import time + +#Starting temperature setpoint 202K + +laser_delay.set_target_value(112).wait() + +mu.set_target_value(21.3).wait() +nu.set_target_value(-125.8).wait() + +#Theta scan +scan.scan1D(mu, 20,24,0.2, 1200, "Th_cm", return_to_initial_values=True) + +#DS @ CM +scan.scan1D(laser_delay, 107, 110.2, 0.2, 2400, "DS_range1", return_to_initial_values=False) +scan.scan1D(laser_delay, 110.21, 110.5, 0.01, 2400, "DS_range2", return_to_initial_values=False) +scan.scan1D(laser_delay, 111, 130, 0.5, 2400, "DS_range3", return_to_initial_values=False) + +#DS @ ICM +mu.set_target_value(22.5).wait() +nu.set_target_value(-125.4).wait() +scan.scan1D(laser_delay, 107, 110.2, 0.2, 2400, "DS_range1", return_to_initial_values=False) +scan.scan1D(laser_delay, 110.21, 110.5, 0.01, 2400, "DS_range2", return_to_initial_values=False) +scan.scan1D(laser_delay, 111, 130, 0.5, 2400, "DS_range3", return_to_initial_values=False) + +lakeshore.set_target_value(207).wait() +time.sleep(30*60) + +laser_delay.set_target_value(112).wait() + +mu.set_target_value(21.3).wait() +nu.set_target_value(-125.8).wait() + +#Theta scan +scan.scan1D(mu, 20,24,0.2, 1200, "Th_cm", return_to_initial_values=True) + +#DS @ CM +scan.scan1D(laser_delay, 107, 110.2, 0.2, 2400, "DS_range1", return_to_initial_values=False) +scan.scan1D(laser_delay, 110.21, 110.5, 0.01, 2400, "DS_range2", return_to_initial_values=False) +scan.scan1D(laser_delay, 111, 130, 0.5, 2400, "DS_range3", return_to_initial_values=False) + +#DS @ ICM +mu.set_target_value(22.5).wait() +nu.set_target_value(-125.4).wait() +scan.scan1D(laser_delay, 107, 110.2, 0.2, 2400, "DS_range1", return_to_initial_values=False) +scan.scan1D(laser_delay, 110.21, 110.5, 0.01, 2400, "DS_range2", return_to_initial_values=False) +scan.scan1D(laser_delay, 111, 130, 0.5, 2400, "DS_range3", return_to_initial_values=False) + + +lakeshore.set_target_value(212).wait() +time.sleep(30*60) + +laser_delay.set_target_value(112).wait() + +mu.set_target_value(21.3).wait() +nu.set_target_value(-125.8).wait() + +#Theta scan +scan.scan1D(mu, 20,24,0.2, 1200, "Th_cm", return_to_initial_values=True) + +#DS @ CM +scan.scan1D(laser_delay, 107, 110.2, 0.2, 2400, "DS_range1", return_to_initial_values=False) +scan.scan1D(laser_delay, 110.21, 110.5, 0.01, 2400, "DS_range2", return_to_initial_values=False) +scan.scan1D(laser_delay, 111, 130, 0.5, 2400, "DS_range3", return_to_initial_values=False) + +#DS @ ICM +mu.set_target_value(22.5).wait() +nu.set_target_value(-125.4).wait() +scan.scan1D(laser_delay, 107, 110.2, 0.2, 2400, "DS_range1", return_to_initial_values=False) +scan.scan1D(laser_delay, 110.21, 110.5, 0.01, 2400, "DS_range2", return_to_initial_values=False) +scan.scan1D(laser_delay, 111, 130, 0.5, 2400, "DS_range3", return_to_initial_values=False) + diff --git a/qspace.py b/qspace.py index 75533f1..a64419a 100644 --- a/qspace.py +++ b/qspace.py @@ -11,6 +11,7 @@ from slic.devices.device import Device from slic.devices.simpledevice import SimpleDevice from slic.utils.printing import printable_table +from constraints import ExtraConstraint INDICES = { "h": 0, @@ -87,6 +88,13 @@ class QSpace3D(Device): for name, value in kwargs.items(): setattr(self.dc.cons, name, value) + def get_position(self, *args, extra_cons=None): + wl = self.wavelength.get_current_value() + res = self.dc.hkl.get_position(*args, wl) + if extra_cons: + res = [r for r in res if extra_cons(_flatten_get_position_result(r))] + return res + def hard_constraints(x): if x["betain"]<0: return False @@ -115,6 +123,13 @@ class QSpace3D(Device): +def _flatten_get_position_result(x): + d0, d1 = x + d0 = d0.asdict + return dict(**d0, **d1) + + + class QSpace1D(Adjustable): def __init__(self, ID, index, dc, motors, wavelength): diff --git a/tth.py b/tth.py new file mode 100644 index 0000000..dca84af --- /dev/null +++ b/tth.py @@ -0,0 +1,57 @@ +from time import sleep +import numpy as np +from epics import PV + +from logzero import logger as log + +from slic.core.adjustable import Adjustable +from slic.core.adjustable import PVAdjustable +from slic.core.scanner.scanbackend import wait_for_all #, stop_all +from slic.devices.general.motor import Motor + + +class LakeShore(Adjustable): + + def __init__(self, ID="Temp", units="T", accuracy=0, name="" ): + super().__init__(ID, name=name, units=units) + self.SP_RBV_T=PVAdjustable("SATES30-LS336:LOOP1_SP", "SATES30-LS336:A_RBV", name = "Temp") + self.accuracy=accuracy + + def set_target_value(self, value): + t_T= self.SP_RBV_T.set_target_value(value) + t_T.wait() + + def get_current_value(self): + return self.SP_RBV_T.get_current_value() + + def is_moving(self): + delta = abs(self.SP_RBV_T.pvs.setvalue.get() - self.SP_RBV_T.pvs.readback.get() ) + return (delta > self.accuracy) + + + + + + + + +class Coupled_tth(Adjustable): + + + def __init__(self, ID="tth", units="deg", delta=0, name="" ): + super().__init__(ID, name=name, units=units) + self.SRY = Motor("SATES30-RIXS:MOT_SRY.VAL") + self.DRY = Motor("SATES30-RIXS:MOT_DRY.VAL") + self.delta = delta + + def set_target_value(self, value): + s_SRY = 90 - value + self.delta + s_DRY = -2*value + t_SRY = self.SRY.set_target_value(s_SRY) + t_DRY = self.DRY.set_target_value(s_DRY) + t_SRY.wait() + t_DRY.wait() + def get_current_value(self): + return self.DRY.get_current_value()*(-.5) + def is_moving(self): + return any([self.SRY.is_moving(),self.DRY.is_moving()]) diff --git a/undulator.py b/undulator.py index d190c55..92e0a1c 100644 --- a/undulator.py +++ b/undulator.py @@ -106,7 +106,7 @@ class Undulators(Adjustable): class Undulator(PVAdjustable): - def __init__(self, name, accuracy=0.0005): + def __init__(self, name, accuracy=0.5): 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)