From e7820ccab5fd9e5e7a6e63f68643509c17ddd808 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Wed, 22 Jun 2022 11:40:45 +0200 Subject: [PATCH 01/52] many addition cleanup, for savoini, started to include pointing monitors --- eco/bernina/bernina.py | 148 ++++++++++++++++++++++-- eco/detector/jungfrau.py | 6 +- eco/devices_general/cameras_swissfel.py | 4 +- eco/devices_general/motors.py | 4 +- eco/loptics/bernina_laser.py | 115 ++++++++++++++++++ eco/loptics/position_monitors.py | 25 ++++ eco/microscopes/microscopes.py | 4 +- eco/timing/lasertiming_edwin.py | 10 ++ eco/timing/sequencer.py | 28 ++++- eco/utilities/config.py | 9 +- 10 files changed, 325 insertions(+), 28 deletions(-) create mode 100644 eco/loptics/position_monitors.py diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 7d161d3..89a7c37 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -1,4 +1,9 @@ +import json +from pathlib import Path +from eco.acquisition.scan import NumpyEncoder from eco.elements.adjustable import AdjustableFS +from eco.elements.adjustable import AdjustableVirtual +from eco.loptics.bernina_experiment import DelayCompensation # from eco.endstations.bernina_sample_environments import Organic_crystal_breadboard_old from eco.motion.smaract import SmaractController @@ -608,10 +613,36 @@ namespace.append_obj( ) -def _append_namesace_status_to_scan(scan): - scan.scan_info["scan_parameters"]["namespace_status"] = namespace.get_status( - base=None +def _append_namesace_status_to_scan(scan, daq=daq, namespace=namespace): + namespace_status = namespace.get_status(base=None) + stat = {"status_run_start": namespace_status} + scan.status = stat + + +def _write_namespace_status_to_scan(scan, daq=daq, namespace=namespace): + namespace_status = namespace.get_status(base=None) + scan.status["status_run_end"] = namespace_status + runno = daq.get_last_run_number() + pgroup = daq.pgroup + tmpdir = Path(f"/sf/bernina/data/{pgroup}/res/tmp/stat_run{runno:04d}") + tmpdir.mkdir(exist_ok=True, parents=True) + statusfile = tmpdir / Path("status.json") + if not Path(statusfile).exists(): + with open(statusfile, "w") as f: + json.dump(scan.status, f, sort_keys=True, cls=NumpyEncoder, indent=4) + else: + with open(statusfile, "r+") as f: + f.seek(0) + json.dump(scan.status, f, sort_keys=True, cls=NumpyEncoder, indent=4) + f.truncate() + response = daq.append_aux( + statusfile.resolve().as_posix(), + pgroup=pgroup, + run_number=runno, ) + print("################") + print(response.json()) + print("################") def _append_namespace_aliases_to_scan(scan): @@ -625,12 +656,61 @@ def _message_end_scan(scan): e.stop() -def _copy_scan_info_to_raw(scan, daq=daq): - run_number = daq.get_last_run_number() +# def _copy_scan_info_to_raw(scan, daq=daq): +# run_number = daq.get_last_run_number() +# pgroup = daq.pgroup +# print(f"Copying info file to run {run_number} to the raw directory of {pgroup}.") +# response = daq.append_aux( +# scan.scan_info_filename, pgroup=pgroup, run_number=run_number +# ) +# print(f"Status: {response.json()['status']} Message: {response.json()['message']}") + +def _create_general_run_info(scan,daq=daq): + with open(scan.scan_info_filename,'r') as f: + si = json.load(f) + + info = {} + # general info, potentially automatically filled + info['general'] = {} + # individual data filled by daq/writers/user through api + info['start'] = {} + info['end'] = {} + info['steps'] = [] + + +def _copy_scan_info_to_raw(scan,daq=daq): + + # get data that should come later from api or similar. + run_directory = list(Path(f"/sf/bernina/data/{daq.pgroup}/raw").glob(f'run{scan.run_number:04d}*'))[0].as_posix() + with open(scan.scan_info_filename,'r') as f: + si = json.load(f) + + # correct some data in there (relative paths for now) + from os.path import relpath + newfiles = [] + for files in si['scan_files']: + newfiles.append([relpath(file,run_directory) for file in files]) + + si['scan_files'] = newfiles + + # save temprary file and send then to raw + runno = daq.get_last_run_number() pgroup = daq.pgroup - print(f"Copying info file to run {run_number} to the raw directory of {pgroup}.") + tmpdir = Path(f"/sf/bernina/data/{pgroup}/res/tmp/info_run{runno:04d}") + tmpdir.mkdir(exist_ok=True, parents=True) + scaninfofile = tmpdir / Path("scan_info_rel.json") + if not Path(scaninfofile).exists(): + with open(scaninfofile, "w") as f: + json.dump(si, f, sort_keys=True, cls=NumpyEncoder, indent=4) + else: + with open(scaninfofile, "r+") as f: + f.seek(0) + json.dump(si, f, sort_keys=True, cls=NumpyEncoder, indent=4) + f.truncate() + + print(f"Copying info file to run {runno} to the raw directory of {pgroup}.") response = daq.append_aux( - scan.scan_info_filename, pgroup=pgroup, run_number=run_number + scaninfofile.as_posix(), pgroup=pgroup, run_number=runno ) print(f"Status: {response.json()['status']} Message: {response.json()['message']}") @@ -658,10 +738,11 @@ def _increment_daq_run_number(scan, daq=daq): callbacks_start_scan = [] callbacks_start_scan = [lambda scan: namespace.init_all(silent=False)] -callbacks_start_scan.append(_append_namespace_aliases_to_scan) callbacks_start_scan.append(_append_namesace_status_to_scan) +callbacks_start_scan.append(_append_namespace_aliases_to_scan) callbacks_start_scan.append(_increment_daq_run_number) callbacks_end_scan = [_message_end_scan] +callbacks_end_scan.append(_write_namespace_status_to_scan) callbacks_end_scan.append(_copy_scan_info_to_raw) @@ -853,6 +934,14 @@ namespace.append_obj( name="las", module_name="eco.loptics.bernina_laser", ) + +namespace.append_obj( + "PositionMonitors", + lazy=True, + name="las_pointing", + module_name="eco.loptics.bernina_laser", +) + # namespace.append_obj( # "IncouplingCleanBernina", # lazy=False, @@ -969,7 +1058,7 @@ class THz_in_air(Assembly): self._append(SmaractRecord, "SARES23:ESB1", name="thz_mir_z", is_setting=True) self._append(SmaractRecord, "SARES23:ESB8", name="thz_mir_Ry", is_setting=True) self._append(SmaractRecord, "SARES23:ESB2", name="thz_mir_Rz", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB6", name="focus_x", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB6", name="focus_z", is_setting=True) self._append( MotorRecord, "SARES20-MF1:MOT_4", @@ -977,11 +1066,44 @@ class THz_in_air(Assembly): is_setting=True, is_display=True, ) - self._append(SmaractRecord, "SARES23:ESB14", name="focus_z", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB13", name="focus_Rx", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB14", name="focus_x", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB13", name="focus_Rz", is_setting=True) self._append(SmaractRecord, "SARES23:ESB15", name="focus_Ry", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB11", name="focus_Rz", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB11", name="focus_Rx", is_setting=True) + self._append(SmaractRecord, "SARES23:LIC18", name="thz_wp", is_setting=True) + self._append(SmaractRecord, "SARES23:LIC16", name="delaystage_thz", is_setting=True) + self._append(DelayTime, self.delaystage_thz, name="delay_thz", is_setting=True) + self._append(MotorRecord, "SLAAR21-LMOT-M521:MOTOR_1", name="delaystage_800_pump", is_setting=True) + self._append(DelayTime, self.delaystage_800_pump, name="delay_800_pump", is_setting=True) + + self.delay_thz = DelayTime(self.delaystage_thz, name="delay_thz") + self.thz_polarization = AdjustableVirtual( + [self.crystal_ROT, self.thz_wp], + self.thz_pol_get, + self.thz_pol_set, + name="thz_polarization", + + + ) + self.combined_delay = AdjustableVirtual( + [self.delay_thz, self.delay_800_pump], + self.delay_get, + self.delay_set, + name="combined_delay", + + ) + def thz_pol_set(self, val): + return 1.0 * val, 1.0 / 2 * val + + def thz_pol_get(self, val, val2): + return 1.0 * val + + def delay_set(self, val): + return 1.0 * val, 1.0 * val + + def delay_get(self, val, val2): + return 1.0 * val namespace.append_obj( THz_in_air, @@ -1175,6 +1297,8 @@ except: # namespace.append_obj("Xom", module_name="xom", name="xom", lazy=True) +namespace.init_all() + ############## maybe to be recycled ################### # { diff --git a/eco/detector/jungfrau.py b/eco/detector/jungfrau.py index 9d80dd3..4a8379e 100644 --- a/eco/detector/jungfrau.py +++ b/eco/detector/jungfrau.py @@ -68,12 +68,12 @@ class Jungfrau(Assembly): filepath = Path(f"/sf/jungfrau/config/gainMaps/{self.jf_id}/gains.h5") if filepath.exists(): - return filepath.resolve().as_posix() + return filepath.as_posix() else: - raise Exception(f"File {filepath.resolve().as_posix()} seems not to exist!") + raise Exception(f"File {filepath.as_posix()} seems not to exist!") def get_present_pedestal_filename(self): searchpath = Path(f"/sf/jungfrau/data/pedestal/{self.jf_id}") filelist = list(searchpath.glob("*.h5")) times = [datetime.strptime(f.stem, "%Y%m%d_%H%M%S") for f in filelist] - return filelist[times.index(max(times))].resolve().as_posix() + return filelist[times.index(max(times))].as_posix() diff --git a/eco/devices_general/cameras_swissfel.py b/eco/devices_general/cameras_swissfel.py index 28c5f54..050b2a9 100644 --- a/eco/devices_general/cameras_swissfel.py +++ b/eco/devices_general/cameras_swissfel.py @@ -338,11 +338,11 @@ class CameraBasler(Assembly): ) def _set_params(self, *args): - self.running(0) + self.running(1) for ob, val in args: ob(val) self._set_parameters(1) - self.running(1) + self.running(2) def gui(self): self._run_cmd( diff --git a/eco/devices_general/motors.py b/eco/devices_general/motors.py index a33a855..b1912b5 100755 --- a/eco/devices_general/motors.py +++ b/eco/devices_general/motors.py @@ -907,7 +907,7 @@ class SmaractRecord(Assembly): AdjustablePv, self.pvname + ".HOMR", name="home_forward", - is_setting=True, + is_setting=False, is_status=False, is_display=False, ) @@ -915,7 +915,7 @@ class SmaractRecord(Assembly): AdjustablePv, self.pvname + ".HOMR", name="home_reverse", - is_setting=True, + is_setting=False, is_status=False, is_display=False, ) diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index 37d1a4f..badb2fe 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -1,6 +1,11 @@ +from eco.loptics.position_monitors import CameraPositionMonitor from ..elements.assembly import Assembly +from functools import partial from ..devices_general.motors import SmaractStreamdevice, MotorRecord from ..elements.adjustable import AdjustableMemory, AdjustableVirtual, AdjustableFS +from ..epics.adjustable import AdjustablePv, AdjustablePvEnum +from ..epics.detector import DetectorPvData +from ..devices_general.detectors import DetectorVirtual from ..timing.lasertiming_edwin import XltEpics import colorama import datetime @@ -20,6 +25,106 @@ class IncouplingCleanBernina(Assembly): self._append(SmaractStreamdevice, "SARES23-LIC15", name="transl_vertical") self._append(MotorRecord, "SARES20-MF2:MOT_5", name="transl_horizontal") +flag_names_filter_wheel = [ + "error", + "proc_tongle", + "connected", + "moving", + "homed", + "remote_operation", +] + + +class FilterWheelFlags(Assembly): + def __init__(self, flags, name="flags"): + super().__init__(name=name) + self._flags = flags + for flag_name in flag_names_filter_wheel: + self._append( + DetectorVirtual, + [self._flags], + partial(self._get_flag_name_value, flag_name=flag_name), + name=flag_name, + is_status=True, + is_display=True, + ) + + def _get_flag_name_value(self, value, flag_name=None): + index = flag_names_filter_wheel.index(flag_name) + return int("{0:015b}".format(int(value))[-1 * (index + 1)]) == 1 + + +class FilterWheel(Assembly): + def __init__(self, pvname, name=None): + super().__init__(name=name) + self.pvname = pvname + self._append(AdjustablePvEnum, f"{pvname}.VAL", name = "_val", is_setting=True) + self._append(AdjustablePvEnum, f"{pvname}.RBV", name = "_rb", is_setting=True) + self._append(AdjustablePv, f"{pvname}.CMD", name = "_cmd", is_setting=False) + self.set_remote_operation() + self._append( + DetectorPvData, + self.pvname + ".STA", + name="_flags", + is_setting=False, + is_display=False, + ) + self._append( + FilterWheelFlags, + self._flags, + name="flags", + is_display="recursive", + is_setting=False, + is_status=True, + ) + + def set_remote_operation(self): + self._val(7) + + def set_manual_operation(self): + self._val(8) + + def home(self): + self.set_remote_operation() + self._val(6) + + def is_moving(self): + pass + + + + +class FilterWheelAttenuator(Assembly): + def __init__(self, pvname, name=None): + super().__init__(name=name) + self._append(FilterWheel, pvname = pvname + "IFW_A", name="wheel_1") + self._append(FilterWheel, pvname = pvname + "IFW_B", name="wheel_2") + + self.targets_1 = { + "t": 10**-np.array([0.2, 0.3, 0.5, 0.6, 1.0]), + "pos": np.array([1,2,3,4,5]), + } + self.targets_2 = { + "t":10**-np.array([0.2, 0.3, 0.4, 0.5, 0.6]), + "pos": np.array([1,2,3,4,5]), + } + + self._calc_transmission() + + def _calc_transmission(self): + t1 = self.targets_1["t"] + t2 = self.targets_2["t"] + t_comb = ( + (np.expand_dims(t1, axis=0)).T * (np.expand_dims(t2, axis=0)) + ).flatten() + pos_comb = np.array( + [[p1, p2] for p1 in self.targets_1["pos"] for p2 in self.targets_2["pos"]] + ) + self.transmissions = {"t": t_comb, "pos": pos_comb} + + def home(self): + self.wheel_1.home() + self.wheel_2.home() class LaserBernina(Assembly): def __init__(self, pvname, name=None): @@ -181,3 +286,13 @@ class DelayCompensation(AdjustableVirtual): s += f"{(self.get_current_value()*ureg.second).to_compact():P~6.3f}" s += f"{colorama.Style.RESET_ALL}" return s + + + +class PositionMonitors(Assembly): + def __init__(self,name=None): + super().__init__(name=name) + self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C551', name='post_compressor_focus', is_display='recursive', is_status=True) + self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C552', name='post_compressor_position', is_display='recursive', is_status=True) + # self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C541', name='cam541') + # self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C542', name='cam542') diff --git a/eco/loptics/position_monitors.py b/eco/loptics/position_monitors.py new file mode 100644 index 0000000..d3260af --- /dev/null +++ b/eco/loptics/position_monitors.py @@ -0,0 +1,25 @@ +from eco.epics.detector import DetectorPvDataStream +from eco.epics.adjustable import AdjustablePv +from eco import Assembly + +class CameraPositionMonitor(Assembly): + def __init__(self,pvname,name=None): + super().__init__(name=name) + self.pvname = pvname + self._append(DetectorPvDataStream,pvname+':FIT-XPOS',name='xpos_raw') + self._append(DetectorPvDataStream,pvname+':FIT-YPOS',name='ypos_raw') + self._append(DetectorPvDataStream,pvname+':FIT-XWID',name='xwidth_raw') + self._append(DetectorPvDataStream,pvname+':FIT-YWID',name='ywidth_raw') + self._append(DetectorPvDataStream,pvname+':FIT-XCOM',name='xcom_raw') + self._append(DetectorPvDataStream,pvname+':FIT-YCOM',name='ycom_raw') + self._append(DetectorPvDataStream,pvname+':FIT-XPOS_EGU',name='xpos') + self._append(DetectorPvDataStream,pvname+':FIT-YPOS_EGU',name='ypos') + self._append(DetectorPvDataStream,pvname+':FIT-XWID_EGU',name='xwidth') + self._append(DetectorPvDataStream,pvname+':FIT-YWID_EGU',name='ywidth') + self._append(AdjustablePv,pvname+':XCALIB',name='xcalib_gradient', is_setting=True) + self._append(AdjustablePv,pvname+':YCALIB',name='ycalib_gradient', is_setting=True) + self._append(AdjustablePv,pvname+':XCALIB-OFFS',name='xcalib_offset', is_setting=True) + self._append(AdjustablePv,pvname+':YCALIB-OFFS',name='ycalib_offset', is_setting=True) + + + \ No newline at end of file diff --git a/eco/microscopes/microscopes.py b/eco/microscopes/microscopes.py index 1e8c833..1d0d331 100644 --- a/eco/microscopes/microscopes.py +++ b/eco/microscopes/microscopes.py @@ -11,8 +11,6 @@ class MicroscopeMotorRecord(Assembly): def __init__( self, pvname_camera=None, - camserver_alias=None, - # camserver_alias=None, pvname_zoom=None, pvname_focus=None, name=None, @@ -22,7 +20,7 @@ class MicroscopeMotorRecord(Assembly): self._append( CameraBasler, pvname_camera, - camserver_alias=camserver_alias, + camserver_alias=name, name="camera", is_setting=True, is_display="recursive", diff --git a/eco/timing/lasertiming_edwin.py b/eco/timing/lasertiming_edwin.py index fb609f8..2c44702 100644 --- a/eco/timing/lasertiming_edwin.py +++ b/eco/timing/lasertiming_edwin.py @@ -10,6 +10,7 @@ from ..elements.adjustable import ( tweak_option, ) from ..epics.adjustable import AdjustablePv, AdjustablePvEnum +from ..epics.detector import DetectorPvData from ..aliases import append_object_to_object, Alias from ..elements.assembly import Assembly @@ -98,6 +99,7 @@ class XltEpics(Assembly): self.pvname = pvname self.settings_collection.append(self, force=True) self.status_collection.append(self, force=True) + self.display_collection.append(self, force=True) self._append( AdjustablePvEnum, self.pvname + ":SHOTDELAY", @@ -149,6 +151,14 @@ class XltEpics(Assembly): is_setting=True, is_display=True, ) + # self._append( + # DetectorPvData, + # "SLAAR-LGEN:DLY_OFFS2", + # name="delay_dial", + # is_setting=False, + # is_display=True, + # ) + self._delay_dial_rb = PV("SLAAR-LGEN:DLY_OFFS2") self.alias.append( Alias("delay_dial_rb", "SLAAR-LGEN:DLY_OFFS2", channeltype="CA") diff --git a/eco/timing/sequencer.py b/eco/timing/sequencer.py index eedcee7..446287f 100644 --- a/eco/timing/sequencer.py +++ b/eco/timing/sequencer.py @@ -97,29 +97,47 @@ class CtaSequencer(Assembly): return arrays - def append_sequence_step(self, code, step_delay): + def append_sequence_step(self, code, step_delay, send_immediately=True): if code not in self.event_code_sequences.keys(): raise Exception( f"Eventcode {code} is not within the allowed or configured eventcodes for the sequencer" ) oldlength = self.length.get_current_value() newlength = oldlength + step_delay - changes = [] + + self.new_sequences = {} for i, ec in self.event_code_sequences.items(): if oldlength == 0: o = [] else: o = list(ec.get_current_value()) if i == code: - n = o + [0] * (newlength - oldlength - 1) + [1] + ind = newlength - oldlength - 1 + if ind < 0: + o[newlength-1] = 1 + n=o + else: + n = o + [0] * (newlength - oldlength - 1) + [1] else: n = o + [0] * (newlength - oldlength) + self.new_sequences[i] = n # print(o, n) - changes.append(ec.set_target_value(n)) + + if send_immediately: + self.send_new_sequences() + + def send_new_sequences(self): + for i, n in self.new_sequences.items(): + + changes = [] + changes.append(self.event_code_sequences[i].set_target_value(n)) for change in changes: change.wait() # self.event_code_sequences[code]._value[newlength - 1] = 1 + lengths = [len(n) for i, n in self.new_sequences.items()] + newlength = lengths[0] + print(f"newlength is {newlength}, lengths are {lengths}") self.length.set_target_value(newlength).wait() @@ -142,7 +160,7 @@ class CtaSequencer(Assembly): tsteps = is_present_array.nonzero()[0] for step in tsteps: if not step in seq_red.keys(): - seq_red[step] = [] + seq_red[int(step)] = [] seq_red[step].append(code) return seq_red diff --git a/eco/utilities/config.py b/eco/utilities/config.py index e4fccee..2229d91 100644 --- a/eco/utilities/config.py +++ b/eco/utilities/config.py @@ -406,7 +406,7 @@ class Namespace(Assembly): # if raise_errors: # raise expt - def get_initialized_aliases(self): + def get_initialized_aliases(self, channeltypes=[]): aliases = [] has_no_aliases = [] for tn, tv in self.initialized_items.items(): @@ -414,6 +414,13 @@ class Namespace(Assembly): aliases += tv.alias.get_all() except: has_no_aliases.append(tn) + aliases_out = [] + for channeltype in channeltypes: + for alias in aliases: + if alias['channeltype']==channeltype: + aliases_out.append(alias) + if not channeltypes: + aliases_out = aliases return aliases, has_no_aliases def append_obj( From adfbbe4e868e2ca3b2ec33b1c0295695541a6de8 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Sat, 25 Jun 2022 10:55:23 +0200 Subject: [PATCH 02/52] upgrade of the adjustable value_property --- eco/acquisition/daq_client.py | 35 +++++++------ eco/bernina/bernina.py | 95 ++++++++++++++++++++++------------ eco/elements/adjustable.py | 27 +++++++--- eco/loptics/bernina_laser.py | 2 + eco/loptics/energy_monitors.py | 25 +++++++++ 5 files changed, 129 insertions(+), 55 deletions(-) create mode 100644 eco/loptics/energy_monitors.py diff --git a/eco/acquisition/daq_client.py b/eco/acquisition/daq_client.py index 8ff8b84..215b4de 100644 --- a/eco/acquisition/daq_client.py +++ b/eco/acquisition/daq_client.py @@ -172,10 +172,10 @@ class Daq(Assembly): timeout=self.timeout, ).json() ) - - runno = response['run_number'] - filenames = response['files'] + runno = response["run_number"] + + filenames = response["files"] # filenames = [ # (directory_base / Path(filename_format.format(runno))) @@ -186,27 +186,27 @@ class Daq(Assembly): return runno, filenames - def get_next_run_number(self,pgroup=None): + def get_next_run_number(self, pgroup=None): if pgroup is None: pgroup = self.pgroup res = requests.get( f"{self.broker_address}/get_next_run_number", - json={'pgroup':pgroup}, + json={"pgroup": pgroup}, timeout=self.timeout, - ) - assert res.ok, f'Getting last run number failed {res.raise_for_status()}' - return int(res.json()['message']) + ) + assert res.ok, f"Getting last run number failed {res.raise_for_status()}" + return int(res.json()["message"]) - def get_last_run_number(self,pgroup=None): + def get_last_run_number(self, pgroup=None): if pgroup is None: pgroup = self.pgroup res = requests.get( f"{self.broker_address}/get_last_run_number", - json={'pgroup':pgroup}, + json={"pgroup": pgroup}, timeout=self.timeout, - ) - assert res.ok, f'Getting last run number failed {res.raise_for_status()}' - return int(res.json()['message']) + ) + assert res.ok, f"Getting last run number failed {res.raise_for_status()}" + return int(res.json()["message"]) def get_detector_frequency(self): return self._event_master.event_codes[ @@ -243,16 +243,17 @@ class Daq(Assembly): f"{self.broker_address}/take_pedestal", json=parameters ).json() - def append_aux(self,*file_names,run_number=None,pgroup=None): + def append_aux(self, *file_names, run_number=None, pgroup=None): if pgroup is None: pgroup = self.pgroup if run_number is None: run_number = self.get_last_run_number() return requests.post( - self.broker_address_aux+'/copy_user_files', - json={'pgroup': pgroup, 'run_number': run_number, 'files': file_names} - ) + self.broker_address_aux + "/copy_user_files", + json={"pgroup": pgroup, "run_number": run_number, "files": file_names}, + ) + def validate_response(resp): if resp.get("status") == "ok": diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 89a7c37..93caf25 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -71,8 +71,8 @@ namespace.append_obj( "Run_Table2", name="run_table", module_name="eco.utilities.runtable", - exp_id=config_bernina.pgroup.value, - exp_path=f"/sf/bernina/data/{config_bernina.pgroup.value}/res/run_table/", + exp_id=config_bernina.pgroup._value, + exp_path=f"/sf/bernina/data/{config_bernina.pgroup._value}/res/run_table/", devices="bernina", keydf_fname="/sf/bernina/config/src/python/gspread/gspread_keys.pkl", cred_fname="/sf/bernina/config/src/python/gspread/pandas_push", @@ -473,7 +473,7 @@ namespace.append_obj( Id="SARES21-XRD", configuration=config_bernina.xrd_config(), diff_detector={"jf_id": "JF01T03V01"}, - invert_kappa_ellbow=config_bernina.invert_kappa_ellbow.value, + invert_kappa_ellbow=config_bernina.invert_kappa_ellbow._value, name="xrd", lazy=True, ) @@ -665,33 +665,37 @@ def _message_end_scan(scan): # ) # print(f"Status: {response.json()['status']} Message: {response.json()['message']}") -def _create_general_run_info(scan,daq=daq): - with open(scan.scan_info_filename,'r') as f: + +def _create_general_run_info(scan, daq=daq): + with open(scan.scan_info_filename, "r") as f: si = json.load(f) info = {} # general info, potentially automatically filled - info['general'] = {} + info["general"] = {} # individual data filled by daq/writers/user through api - info['start'] = {} - info['end'] = {} - info['steps'] = [] + info["start"] = {} + info["end"] = {} + info["steps"] = [] -def _copy_scan_info_to_raw(scan,daq=daq): - +def _copy_scan_info_to_raw(scan, daq=daq): + # get data that should come later from api or similar. - run_directory = list(Path(f"/sf/bernina/data/{daq.pgroup}/raw").glob(f'run{scan.run_number:04d}*'))[0].as_posix() - with open(scan.scan_info_filename,'r') as f: + run_directory = list( + Path(f"/sf/bernina/data/{daq.pgroup}/raw").glob(f"run{scan.run_number:04d}*") + )[0].as_posix() + with open(scan.scan_info_filename, "r") as f: si = json.load(f) # correct some data in there (relative paths for now) from os.path import relpath + newfiles = [] - for files in si['scan_files']: - newfiles.append([relpath(file,run_directory) for file in files]) - - si['scan_files'] = newfiles + for files in si["scan_files"]: + newfiles.append([relpath(file, run_directory) for file in files]) + + si["scan_files"] = newfiles # save temprary file and send then to raw runno = daq.get_last_run_number() @@ -707,11 +711,9 @@ def _copy_scan_info_to_raw(scan,daq=daq): f.seek(0) json.dump(si, f, sort_keys=True, cls=NumpyEncoder, indent=4) f.truncate() - + print(f"Copying info file to run {runno} to the raw directory of {pgroup}.") - response = daq.append_aux( - scaninfofile.as_posix(), pgroup=pgroup, run_number=runno - ) + response = daq.append_aux(scaninfofile.as_posix(), pgroup=pgroup, run_number=runno) print(f"Status: {response.json()['status']} Message: {response.json()['message']}") @@ -1071,40 +1073,69 @@ class THz_in_air(Assembly): self._append(SmaractRecord, "SARES23:ESB15", name="focus_Ry", is_setting=True) self._append(SmaractRecord, "SARES23:ESB11", name="focus_Rx", is_setting=True) self._append(SmaractRecord, "SARES23:LIC18", name="thz_wp", is_setting=True) - self._append(SmaractRecord, "SARES23:LIC16", name="delaystage_thz", is_setting=True) + self._append( + SmaractRecord, "SARES23:LIC16", name="delaystage_thz", is_setting=True + ) self._append(DelayTime, self.delaystage_thz, name="delay_thz", is_setting=True) - self._append(MotorRecord, "SLAAR21-LMOT-M521:MOTOR_1", name="delaystage_800_pump", is_setting=True) - self._append(DelayTime, self.delaystage_800_pump, name="delay_800_pump", is_setting=True) - + self._append( + MotorRecord, + "SLAAR21-LMOT-M521:MOTOR_1", + name="delaystage_800_pump", + is_setting=True, + ) + self._append( + DelayTime, self.delaystage_800_pump, name="delay_800_pump", is_setting=True + ) + self._append( + AdjustableFS, + "/photonics/home/gac-bernina/eco/configuration/combined_delta", + name="combined_delta", + default_value=0, + is_setting=True, + ) self.delay_thz = DelayTime(self.delaystage_thz, name="delay_thz") - self.thz_polarization = AdjustableVirtual( + self._append( + AdjustableVirtual, [self.crystal_ROT, self.thz_wp], self.thz_pol_get, self.thz_pol_set, name="thz_polarization", - - ) - self.combined_delay = AdjustableVirtual( + # self.thz_polarization = AdjustableVirtual( + # [self.crystal_ROT, self.thz_wp], + # self.thz_pol_get, + # self.thz_pol_set, + # name="thz_polarization", + # ) + self._append( + AdjustableVirtual, [self.delay_thz, self.delay_800_pump], self.delay_get, self.delay_set, name="combined_delay", - ) + + # self.combined_delay = AdjustableVirtual( + # [self.delay_thz, self.delay_800_pump], + # self.delay_get, + # self.delay_set, + # name="combined_delay", + # ) + def thz_pol_set(self, val): return 1.0 * val, 1.0 / 2 * val def thz_pol_get(self, val, val2): - return 1.0 * val + return 1.0 * val2 def delay_set(self, val): - return 1.0 * val, 1.0 * val + return 1.0 * val + self.combined_delta(), 1.0 * val def delay_get(self, val, val2): return 1.0 * val + namespace.append_obj( THz_in_air, lazy=True, diff --git a/eco/elements/adjustable.py b/eco/elements/adjustable.py index 44b5192..b7bd02e 100644 --- a/eco/elements/adjustable.py +++ b/eco/elements/adjustable.py @@ -246,19 +246,34 @@ def update_changes(Adj): def value_property(Adj, wait_for_change=True, value_name="_value"): if wait_for_change: - def tmp(Adj, value): - Adj.set_target_value(value, hold=False).wait() + def set_target_value_wait(self, value): + self.set_target_value(value, hold=False).wait() + + def get_current_value(self): + o = self.get_current_value() + if hasattr(o, "__setitem__"): + # print("overwriting output class") + + class TempObj(o.__class__): + def __setitem__(oself, *args): + o.__class__.__setitem__(oself, *args) + self._set_target_value_wait(oself) + + return TempObj(o) + else: + return o + + Adj._set_target_value_wait = set_target_value_wait + Adj._get_current_value = get_current_value setattr( Adj, value_name, property( - Adj.get_current_value, - tmp, + Adj._get_current_value, + Adj._set_target_value_wait, ), ) - - Adj.value = property(lambda self: self._value) return Adj diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index badb2fe..93a4e69 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -294,5 +294,7 @@ class PositionMonitors(Assembly): super().__init__(name=name) self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C551', name='post_compressor_focus', is_display='recursive', is_status=True) self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C552', name='post_compressor_position', is_display='recursive', is_status=True) + self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C531', name='opaout_position', is_display='recursive', is_status=True) + self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C511', name='opaout_focus', is_display='recursive', is_status=True) # self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C541', name='cam541') # self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C542', name='cam542') diff --git a/eco/loptics/energy_monitors.py b/eco/loptics/energy_monitors.py new file mode 100644 index 0000000..7c2f85a --- /dev/null +++ b/eco/loptics/energy_monitors.py @@ -0,0 +1,25 @@ +from eco import Assembly +from eco.epics.adjustable import AdjustablePv, AdjustablePvEnum +from eco.epics.detector import DetectorPvData, DetectorPvDataStream + + +class LabMaxEnergyMonitor(Assembly): + def __init__(self,pvname, name=None): + super().__init__(name=name) + self.pvname = pvname + self._append(DetectorPvDataStream, pvname+':READ_SC',name='pulse_energy') + self._append(DetectorPvDataStream, pvname+':ENERGY_AVE100',name='pulse_energy_avg100') + self._append(AdjustablePvEnum, pvname+':READ.SCAN',name='read_mode') + self._append(AdjustablePv, pvname+':SET_FSD',name='output_signal_voltage', is_setting=True) + self._append(AdjustablePvEnum, pvname+':WL_CORR_MODE',name='correct_wavelenght', is_setting=True) + self._append(AdjustablePvEnum, pvname+':TRIG_SOURCE',name='trigger_source', is_setting=True) + self._append(AdjustablePv, pvname+':SET_TRIG_LEVEL',name='output_signal_voltage', is_setting=True) + self._append(DetectorPvData, pvname+':GET_RANGE_SC',name='range', is_setting=True) + self._append(AdjustablePv, pvname+':SELECT_RANGE',name='set_range', is_setting=True) + + + + + + + From 12b8f33175253c0d8b6fb78ae9c8782a7e19ecf1 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Sun, 26 Jun 2022 16:31:29 +0200 Subject: [PATCH 03/52] first version of UB matrix motion implemented --- eco/elements/adjustable.py | 11 +- eco/utilities/recspace.py | 293 ++++++++++++++++++++++++++++++++++++- 2 files changed, 302 insertions(+), 2 deletions(-) diff --git a/eco/elements/adjustable.py b/eco/elements/adjustable.py index b7bd02e..fe2fa8e 100644 --- a/eco/elements/adjustable.py +++ b/eco/elements/adjustable.py @@ -4,8 +4,9 @@ import time from json import load, dump from pathlib import Path from threading import Thread - +import itertools import colorama +import numpy as np from eco.aliases import Alias from eco.devices_general.utilities import Changer @@ -499,6 +500,14 @@ class AdjustableVirtual: *[adj.get_current_value() for adj in self._adjustables] ) + def get_limits(self): + try: + limits = [adj.get_limits() for adj in self._adjustables] + vals = np.array([self._foo_get_current_value(*prod) for prod in itertools.product(*limits)]) + return [np.min(vals), np.max(vals)] + except Exception as e: + print(str(e)) + def reset_current_value_to(self, value): if not self._reset_current_value_to: raise NotImplementedError( diff --git a/eco/utilities/recspace.py b/eco/utilities/recspace.py index cf87c76..ddac978 100644 --- a/eco/utilities/recspace.py +++ b/eco/utilities/recspace.py @@ -2,10 +2,11 @@ from diffcalc.hkl.calc import HklCalculation from diffcalc.hkl.constraints import Constraints from diffcalc.hkl.geometry import Position from diffcalc.ub import calc as dccalc +import pandas as pd # from diffcalc.ub import calc calc import UBCalculation, Crystal from eco.elements.assembly import Assembly -from eco.elements.adjustable import AdjustableMemory +from eco.elements.adjustable import AdjustableMemory, AdjustableFS, AdjustableVirtual from typing import Tuple, Optional @@ -138,3 +139,293 @@ class DiffGeometryYou(Assembly): pass # def __init__(sel): + +class DiffGeometryYou2(Assembly): + def __init__(self, diffractometer_you=None, name=None): + super().__init__(name=name) + # self._append(diffractometer_you,call_obj=False, name='diffractometer') + #self._append(AdjustableMemory, {}, name="contraints") + #self._append(AdjustableMemory, {}, name="unit_cell") + #self._append(AdjustableMemory, [], name="U_matrix") + #self._append(AdjustableMemory, [], name="UB_matrix") + #self._append(AdjustableMemory, [], name="orientations") + self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_constraints', name="constraints", default_value={}) + self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_unit_cell', name="unit_cell", default_value={}) + self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_u_matrix', name="u_matrix", default_value=[]) + self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_ub_matrix', name="ub_matrix", default_value=[]) + self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_orientations', name="orientations", default_value=[]) + self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_reflections', name="reflections", default_value=[]) + self.diffractometer = diffractometer_you + adjs = [ + self.diffractometer.nu(), + self.diffractometer.mu(), + self.diffractometer.delta(), + self.diffractometer.eta(), + self.diffractometer.chi, + self.diffractometer.phi(), + ] + def get_h(val): + return self.get_current_value()[0] + def set_h(val): + return self.calc_angles_unique(h=val) + def get_k(val): + return self.get_current_value()[1] + def set_k(val): + return self.calc_angles_unique(k=val) + def get_l(val): + return self.get_current_value()[2] + def set_l(val): + return self.calc_angles_unique(l=val) + + self._append(AdjustableVirtual, adjs, get_h, set_h, name="h") + self._append(AdjustableVirtual, adjs, get_k, set_k, name="k") + self._append(AdjustableVirtual, adjs, get_l, set_l, name="l") + self._append(AdjustableVirtual, adjs, self.calc_hkl, self.calc_angles_unique, name="hkl") + self.recalculate() + + def new_ub(self): + ### missing: clear ub ### + crystal_name = input("Name of the crystal: ") + a = float(input("Lattice constant: ")) + b = float(input(f"Lattice constant b {(a)}: ") or a) + c = float(input(f"Lattice constant c {(a)}: ") or a) + alpha = float(input("Angle alpha (90): ") or 90) + beta = float(input(f"Angle beta {(alpha)}: ") or alpha) + gamma = float(input(f"Angle gamma {(alpha)}: ") or alpha) + normal = [float(val) for val in input("(h,k,l) surface normal (along YOU z-axis) without brackets and ',' separated: ").split(",")] + inplane = [float(val) for val in input("(h,k,l) in-plane orientation along beam (YOU y-axis) without brackets and ',' separated: ")] + self.set_unit_cell(crystal_name, a, b, c, alpha, beta, gamma) + self.add_orientation(normal, (1,0,0), tag='surface normal') + self.add_orientation(inplane, (0,1,0), tag='in-plane along YOU y axis') + self.calc_ub() + + def get_diffractometer_angle_limits(self): + diff_angle_adjs = { + "nu": self.diffractometer.nu, + "mu": self.diffractometer.mu, + "delta": self.diffractometer.delta, + "eta": self.diffractometer.eta, + "chi": self.diffractometer.chi, + "phi": self.diffractometer.phi + } + limits = {key: val.get_limits() for key, val in diff_angle_adjs.items()} + return limits + + def get_diffractometer_angles(self): + nu = self.diffractometer.nu.get_current_value() + mu = self.diffractometer.mu.get_current_value() + delta = self.diffractometer.delta.get_current_value() + eta = self.diffractometer.eta.get_current_value() + chi = self.diffractometer.chi.get_current_value() + phi = self.diffractometer.phi.get_current_value() + return mu, delta, nu, eta, chi, phi + + def set_unit_cell( + self, name_crystal, a=None, b=None, c=None, alpha=None, beta=None, gamma=None + ): + self.unit_cell.set_target_value( + { + "name": name_crystal, + "a": a, + "b": b, + "c": c, + "alpha": alpha, + "beta": beta, + "gamma": gamma, + } + ) + self.recalculate() + + def recalculate(self): + self.ubcalc = dccalc.UBCalculation("you") + uc = self.unit_cell() + self.ubcalc.set_lattice(uc.pop("name"), **uc) + for ori in self.orientations(): + self.ubcalc.add_orientation(ori.pop("hkl"), ori.pop("xyz"), **ori) + for refl in self.reflections(): + self.ubcalc.add_reflection(refl.pop("hkl"), refl.pop("xyz"), **refl) + self._u_ub_to_dc() + + def add_reflection( + self, + hkl, + position, + energy, + tag=None, + ): + """Add a reference reflection. + + Adds a reflection position in degrees and in the systems internal + representation. + + Parameters + ---------- + hkl : Tuple[float, float, float] + hkl index of the reflection + position: Position + list of diffractometer angles in internal representation in degrees + energy : float + energy of the x-ray beam + tag : Optional[str], default = None + identifying tag for the reflection + """ + + self.ubcalc.add_reflection(hkl, position, energy, tag=tag) + self.reflections.set_target_value( + self.reflections() + + [{"hkl": hkl, "position": position, "energy": energy, "tag": tag}] + ) + + def add_orientation(self, hkl, xyz, position=None, tag=None): + """Add a reference orientation. + + Adds a reference orientation in the diffractometer + coordinate system. + + Parameters + ---------- + hkl : :obj:`tuple` of numbers + hkl index of the reference orientation + xyz : :obj:`tuple` of numbers + xyz coordinate of the reference orientation + position: :obj:`list` or :obj:`tuple` of numbers + list of diffractometer angles in internal representation in degrees + tag : str + identifying tag for the reflection + """ + self.orientations.set_target_value( + self.orientations() + + [{"hkl": hkl, "xyz": xyz, "position": position, "tag": tag}] + ) + self.recalculate() + + def calc_ub(self, idx1=None, idx2=None): + """Calculate UB matrix. + + Calculate UB matrix using two reference reflections and/or + reference orientations. + + By default use the first two reference reflections when provided. + If one or both reflections are not available use one or two reference + orientations to complement mission reflection data. + + Parameters + ---------- + idx1: int or str, optional + The index or the tag of the first reflection or orientation. + idx2: int or str, optional + The index or the tag of the second reflection or orientation. + """ + self.recalculate() + self.ubcalc.calc_ub(idx1, idx2) + self._u_ub_from_dc() + + def fit_ub(self, refine_lattice=False, refine_umatrix=False): + """Refine UB matrix using reference reflections. + + Parameters + ---------- + indices: Sequence[Union[str, int]] + List of reference reflection indices or tags. + refine_lattice: Optional[bool], default = False + Apply refined lattice parameters to the current UB calculation object. + refine_umatrix: Optional[bool], default = False + Apply refined U matrix to the current UB calculation object. + + Returns + ------- + Tuple[np.ndarray, Tuple[str, float, float, float, float, float, float]] + Refined U matrix as NumPy array and refined crystal lattice parameters. + """ + self.recalculate() + self.ubcalc.fit_ub( refine_lattice, refine_umatrix) + self._u_ub_from_dc() + if refine_lattice: + self._lat_from_dc() + + def calc_angles(self, h=None,k=None,l=None, energy=None): + """calculate diffractometer angles for a given h,k,l and energy in eV. + If any of the h, k, l are not given, their current value is used instead. + If the energy is not given, the monochromator energy is used + Shows all solutions neglecting diffractometer limits""" + setvals = [h,k,l] + curvals = [self.h, self.k, self.l] + h,k,l = [curval() if setval == None else setval for setval, curval in zip(setvals, curvals)] + self.recalculate() + cons = Constraints(self.constraints()) + hklcalc = HklCalculation(self.ubcalc, cons) + if energy is None: + energy = 8000 + lam = self.en2lam(energy) + result = hklcalc.get_position(h,k,l,lam) + result = pd.concat([pd.DataFrame.from_dict({**tres[0].asdict,**tres[1]},orient='index', columns=[f'sol. {n}']) for n,tres in enumerate(result)],axis=1) + return result.T + + def calc_angles_unique(self, h=None,k=None,l=None, energy=None): + """calculate unique solution of diffractometer angles for a given h,k,l and energy in eV. + If any of the h, k, l are not given, their current value is used instead. + If the energy is not given, the monochromator energy is used.""" + result = self.calc_angles(h,k,l,energy) + limits = self.get_diffractometer_angle_limits() + s='' + for ang, limit in limits.items(): + if len(s)>0: + s=s+' and ' + s = s+f'{limit[0]} < {ang} < {limit[1]}' + result_f = result.query(s) + if result_f.shape[0] > 1: + print(f"There is not a unique angular configuration to reach ({h},{k},{l}), please change the diffractometer motor soft limits to allow only one of the solutions shown below:") + print(result_f) + return None + elif result_f.shape[0] ==0: + print("There is no angular configuration, which is allowed for the current diffractometer motor soft limits. please check the diffractometer limits.") + print(limits) + print("Solutions") + print(result) + return None + return result_f.array + + + def calc_hkl(self, mu=None, delta=None, nu=None, eta=None, chi=None, phi=None, energy=None): + """calculate (h,k,l) for given diffractometer angles and energy in eV. + If any of the diffractometer angles are not given, their current value is used instead. + If the energy is not given, the monochromator energy is used""" + setvals = [mu, delta, nu, eta, chi, phi] + curvals = self.get_diffractometer_angles() + angs = [curval if setval == None else setval for setval, curval in zip(setvals, curvals)] + pos = Position(*angs) + self.recalculate() + if energy is None: + energy = 8000 + lam = self.en2lam(energy) + cons = Constraints(self.constraints()) + hklcalc = HklCalculation(self.ubcalc, cons) + try: + hkl = hklcalc.get_hkl(pos=pos, wavelength=lam) + except Exception as e: + print(str(e)) + return + return hkl + + def _u_ub_from_dc(self): + self.ub_matrix(self.ubcalc.UB.tolist()) + self.u_matrix(self.ubcalc.U.tolist()) + + def _u_ub_to_dc(self): + if len(self.ub_matrix())>0: + self.ubcalc.set_ub(self.ub_matrix()) + self.ubcalc.set_u(self.u_matrix()) + + def _lat_from_dc(self): + self.set_unit_cell(*self.ubcalc.crystal.get_lattice()[1:]) + + def en2lam(self, en): + """input: energy in eV, returns wavelength in A""" + return 12398.419843320025/en + + def lam2en(self, lam): + """input: wavelength in A, returns energy in eV""" + return 12398.419843320025/lam + + pass + # def __init__(sel): From 6a5b59df11999c1b2f73b2dbce96ec42712b492e Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Fri, 1 Jul 2022 18:38:11 +0200 Subject: [PATCH 04/52] working on reciprocal space calculations --- eco/bernina/bernina.py | 9 +- eco/detector/detectors_psi.py | 3 + eco/elements/adjustable.py | 14 +-- eco/loptics/bernina_experiment.py | 4 + eco/utilities/recspace.py | 184 ++++++++++++++++++------------ 5 files changed, 131 insertions(+), 83 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 93caf25..42d309e 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -55,6 +55,13 @@ namespace.append_obj( lazy=False, ) +namespace.append_obj( + "EventWorker", + name="bs_worker", + module_name="escape.stream", + lazy=False, +) + namespace.append_obj( "BerninaEnv", name="env_log", @@ -1133,7 +1140,7 @@ class THz_in_air(Assembly): return 1.0 * val + self.combined_delta(), 1.0 * val def delay_get(self, val, val2): - return 1.0 * val + return 1.0 * val2 namespace.append_obj( diff --git a/eco/detector/detectors_psi.py b/eco/detector/detectors_psi.py index 3fa018a..3628b6b 100644 --- a/eco/detector/detectors_psi.py +++ b/eco/detector/detectors_psi.py @@ -5,6 +5,7 @@ from epics.pv import PV from bsread.bsavail import pollStream from bsread import dispatcher, source from ..epics import get_from_archive +from escape import stream @get_from_archive @@ -20,6 +21,8 @@ class DetectorBsStream: self._pv = PV(self.pvname) self.alias = Alias(name, channel=bs_channel, channeltype="BS") + self.stream = stream.EscData(source=stream.EventSource(self.bs_channel, None)) + def get_current_value(self, force_bsstream=False): if not force_bsstream: return self._pv.get() diff --git a/eco/elements/adjustable.py b/eco/elements/adjustable.py index fe2fa8e..2455548 100644 --- a/eco/elements/adjustable.py +++ b/eco/elements/adjustable.py @@ -500,13 +500,13 @@ class AdjustableVirtual: *[adj.get_current_value() for adj in self._adjustables] ) - def get_limits(self): - try: - limits = [adj.get_limits() for adj in self._adjustables] - vals = np.array([self._foo_get_current_value(*prod) for prod in itertools.product(*limits)]) - return [np.min(vals), np.max(vals)] - except Exception as e: - print(str(e)) + def check_target_value_within_limits(self, value): + in_lims = [] + values = self._foo_set_target_value_current_value(value) + for val, adj in zip(values, self._adjustables): + lim_low, lim_high = adj.get_limits() + in_lims.append((lim_low < val) and (val < lim_high)) + return all(in_lims) def reset_current_value_to(self, value): if not self._reset_current_value_to: diff --git a/eco/loptics/bernina_experiment.py b/eco/loptics/bernina_experiment.py index 2f63aa5..c97c309 100755 --- a/eco/loptics/bernina_experiment.py +++ b/eco/loptics/bernina_experiment.py @@ -1,3 +1,5 @@ +from eco.elements.assembly import Assembly +from eco.loptics.position_monitors import CameraPositionMonitor from ..aliases import Alias from ..devices_general.motors import MotorRecord, SmaractStreamdevice from ..devices_general.smaract import SmarActRecord @@ -364,3 +366,5 @@ class Laser_Exp: def __repr__(self): return self.get_adjustable_positions_str() + + diff --git a/eco/utilities/recspace.py b/eco/utilities/recspace.py index ddac978..06a72aa 100644 --- a/eco/utilities/recspace.py +++ b/eco/utilities/recspace.py @@ -3,11 +3,13 @@ from diffcalc.hkl.constraints import Constraints from diffcalc.hkl.geometry import Position from diffcalc.ub import calc as dccalc import pandas as pd +import numpy as np # from diffcalc.ub import calc calc import UBCalculation, Crystal from eco.elements.assembly import Assembly from eco.elements.adjustable import AdjustableMemory, AdjustableFS, AdjustableVirtual from typing import Tuple, Optional +from eco.elements.adj_obj import AdjustableObject class CrystalNew(Assembly): @@ -138,53 +140,107 @@ class DiffGeometryYou(Assembly): self.ubcalc.fit_ub(*args, **kwargs) pass - # def __init__(sel): + class DiffGeometryYou2(Assembly): def __init__(self, diffractometer_you=None, name=None): super().__init__(name=name) # self._append(diffractometer_you,call_obj=False, name='diffractometer') - #self._append(AdjustableMemory, {}, name="contraints") - #self._append(AdjustableMemory, {}, name="unit_cell") - #self._append(AdjustableMemory, [], name="U_matrix") - #self._append(AdjustableMemory, [], name="UB_matrix") - #self._append(AdjustableMemory, [], name="orientations") - self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_constraints', name="constraints", default_value={}) - self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_unit_cell', name="unit_cell", default_value={}) - self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_u_matrix', name="u_matrix", default_value=[]) - self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_ub_matrix', name="ub_matrix", default_value=[]) - self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_orientations', name="orientations", default_value=[]) - self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_reflections', name="reflections", default_value=[]) + self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_unit_cell', name="unit_cell", default_value={}, is_setting=True) + self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_u_matrix', name="u_matrix", default_value=[], is_setting=True) + self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_ub_matrix', name="ub_matrix", default_value=[], is_setting=True) + self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_orientations', name="orientations", default_value=[], is_setting=True) + self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_reflections', name="reflections", default_value=[], is_setting=True) self.diffractometer = diffractometer_you - adjs = [ - self.diffractometer.nu(), - self.diffractometer.mu(), - self.diffractometer.delta(), - self.diffractometer.eta(), - self.diffractometer.chi, - self.diffractometer.phi(), - ] - def get_h(val): - return self.get_current_value()[0] - def set_h(val): - return self.calc_angles_unique(h=val) - def get_k(val): - return self.get_current_value()[1] - def set_k(val): - return self.calc_angles_unique(k=val) - def get_l(val): - return self.get_current_value()[2] - def set_l(val): - return self.calc_angles_unique(l=val) + cons = { + 'mu': None, + 'eta': None, + 'chi': None, + 'phi': None, + 'delta': None, + 'nu': None, + 'a_eq_b': None, + 'bin_eq_bout': None, + 'betain': None, + 'betaout': None, + 'qaz': None, + 'naz': None, + 'alpha': None, + 'beta': None, + 'bisect': None, + 'psi': None, + 'omega': None, + } + self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_constraints', name="_constraints", default_value=cons, is_setting=True, is_display=False) + self._append(AdjustableObject, self._constraints, name="constraints", is_setting=False, is_display='recursive') - self._append(AdjustableVirtual, adjs, get_h, set_h, name="h") - self._append(AdjustableVirtual, adjs, get_k, set_k, name="k") - self._append(AdjustableVirtual, adjs, get_l, set_l, name="l") - self._append(AdjustableVirtual, adjs, self.calc_hkl, self.calc_angles_unique, name="hkl") + + cfg = self.diffractometer.configuration + adjs = ['nu', 'mu', 'delta', 'eta', 'chi', 'phi'] + if 'kappa' in cfg: + adjs = ['nu', 'mu', 'delta', 'eta_kap', 'kappa', 'phi_kap'] + adj_keys = [adj if adj in self.diffractometer.__dict__.keys() else adj+'_manual' for adj in adjs] + self._diff_adjs = {adj: self.diffractometer.__dict__[adj_key] for adj, adj_key in zip(adjs, adj_keys)} + + + def get_h(*args, **kwargs): + return self.calc_hkl()[0] + def set_h(val): + return self._calc_angles_unique_diffractometer(h=val) + def get_k(*args, **kwargs): + return self.calc_hkl()[1] + def set_k(val): + return self._calc_angles_unique_diffractometer(k=val) + def get_l(*args, **kwargs): + return self.calc_hkl()[2] + def set_l(val): + return self._calc_angles_unique_diffractometer(l=val) + def get_hkl(*args, **kwargs): + return self.calc_hkl() + + self._append(AdjustableVirtual, list(self._diff_adjs.values()), get_h, set_h, name="h") + self._append(AdjustableVirtual, list(self._diff_adjs.values()), get_k, set_k, name="k") + self._append(AdjustableVirtual, list(self._diff_adjs.values()), get_l, set_l, name="l") + self._append(AdjustableVirtual, list(self._diff_adjs.values()), get_hkl, self._calc_angles_unique_diffractometer, name="hkl") self.recalculate() + def convert_from_you(self, **kwargs): + cfg = self.diffractometer.configuration + if 'kappa' in cfg: + eta_kap, kappa, phi_kap = self.diffractometer.calc_you2kappa(kwargs["eta"],kwargs["chi"],kwargs["phi"]) + kwargs.update({"eta_kap": eta_kap, "kappa": kappa, "phi_kap": phi_kap}) + return [kwargs[key] for key in self._diff_adjs.keys()] + + def convert_to_you(self, nu=None, mu=None, delta=None, eta=None, chi=None, phi=None, eta_kap=None, kappa=None, phi_kap=None): + cfg = self.diffractometer.configuration + if 'kappa' in cfg: + eta, chi, phi = self.diffractometer.calc_kappa2you(eta_kap, kappa, phi_kap) + return nu, mu, delta, eta, chi, phi + + def get_diffractometer_angles(self): + ### assume that all angles exist in diffractometer at least as manual adjustable ### + nu, mu, delta, eta, chi, phi = self.convert_to_you(**{key: adj() for key, adj in self._diff_adjs.items()}) + return mu, delta, nu, eta, chi, phi + + def _calc_angles_unique_diffractometer(self,h,k,l): + angles = self.calc_angles_unique(h,k,l) + return self.convert_from_you(**angles) + + def check_target_value_within_limits(self, **kwargs): + ### virtual adjustables got a new function check_target_value_within_limits(values) + in_lims = [] + target_values = self.convert_from_you(**kwargs) + for val, adj in zip(target_values, self._diff_adjs.values()): + if hasattr(adj, 'get_limits'): + lim_low, lim_high = adj.get_limits() + in_lims.append((lim_low < val) and (val < lim_high)) + else: + raise Exception(f"Failed to get limits of adjustable {adj.name}") + return all(in_lims) + def new_ub(self): ### missing: clear ub ### + ### missing: check ub ### crystal_name = input("Name of the crystal: ") a = float(input("Lattice constant: ")) b = float(input(f"Lattice constant b {(a)}: ") or a) @@ -198,27 +254,7 @@ class DiffGeometryYou2(Assembly): self.add_orientation(normal, (1,0,0), tag='surface normal') self.add_orientation(inplane, (0,1,0), tag='in-plane along YOU y axis') self.calc_ub() - - def get_diffractometer_angle_limits(self): - diff_angle_adjs = { - "nu": self.diffractometer.nu, - "mu": self.diffractometer.mu, - "delta": self.diffractometer.delta, - "eta": self.diffractometer.eta, - "chi": self.diffractometer.chi, - "phi": self.diffractometer.phi - } - limits = {key: val.get_limits() for key, val in diff_angle_adjs.items()} - return limits - - def get_diffractometer_angles(self): - nu = self.diffractometer.nu.get_current_value() - mu = self.diffractometer.mu.get_current_value() - delta = self.diffractometer.delta.get_current_value() - eta = self.diffractometer.eta.get_current_value() - chi = self.diffractometer.chi.get_current_value() - phi = self.diffractometer.phi.get_current_value() - return mu, delta, nu, eta, chi, phi + print("UB was calculated - next please set the constraints and the limits of the diffractometer motors") def set_unit_cell( self, name_crystal, a=None, b=None, c=None, alpha=None, beta=None, gamma=None @@ -352,7 +388,7 @@ class DiffGeometryYou2(Assembly): curvals = [self.h, self.k, self.l] h,k,l = [curval() if setval == None else setval for setval, curval in zip(setvals, curvals)] self.recalculate() - cons = Constraints(self.constraints()) + cons = Constraints(self._constraints()) hklcalc = HklCalculation(self.ubcalc, cons) if energy is None: energy = 8000 @@ -365,25 +401,23 @@ class DiffGeometryYou2(Assembly): """calculate unique solution of diffractometer angles for a given h,k,l and energy in eV. If any of the h, k, l are not given, their current value is used instead. If the energy is not given, the monochromator energy is used.""" - result = self.calc_angles(h,k,l,energy) - limits = self.get_diffractometer_angle_limits() - s='' - for ang, limit in limits.items(): - if len(s)>0: - s=s+' and ' - s = s+f'{limit[0]} < {ang} < {limit[1]}' - result_f = result.query(s) - if result_f.shape[0] > 1: + df = self.calc_angles(h,k,l,energy) + in_lims = np.array([self.check_target_value_within_limits(**df.loc[idx].to_dict()) for idx in df.index]) + idx_in = df.index[in_lims] + idx_out = df.index[~in_lims] + + if len(idx_in) > 1: print(f"There is not a unique angular configuration to reach ({h},{k},{l}), please change the diffractometer motor soft limits to allow only one of the solutions shown below:") - print(result_f) - return None - elif result_f.shape[0] ==0: + print(df.loc[idx_in]) + raise Exception("No unique solution") + elif idx_in ==0: print("There is no angular configuration, which is allowed for the current diffractometer motor soft limits. please check the diffractometer limits.") - print(limits) print("Solutions") - print(result) - return None - return result_f.array + print(df) + raise Exception("No unique solution") + solution_unique = df.loc[idx_in[0]] + + return solution_unique.to_dict() def calc_hkl(self, mu=None, delta=None, nu=None, eta=None, chi=None, phi=None, energy=None): @@ -398,7 +432,7 @@ class DiffGeometryYou2(Assembly): if energy is None: energy = 8000 lam = self.en2lam(energy) - cons = Constraints(self.constraints()) + cons = Constraints(self._constraints()) hklcalc = HklCalculation(self.ubcalc, cons) try: hkl = hklcalc.get_hkl(pos=pos, wavelength=lam) From 6e7e1e58481a13640572a5324b23b7009924ba62 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Sun, 10 Jul 2022 07:51:41 +0200 Subject: [PATCH 05/52] colorbars shown when changing adjustables can now deal with multidimensional values --- eco/bernina/bernina.py | 94 ++++--- eco/bernina/config.py | 28 --- eco/elements/adjustable.py | 29 ++- eco/endstations/bernina_diffractometers.py | 6 +- eco/loptics/bernina_laser.py | 32 ++- eco/utilities/recspace.py | 275 ++++++++++----------- 6 files changed, 225 insertions(+), 239 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 42d309e..400fab8 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -891,14 +891,14 @@ namespace.append_obj( # pvname_zoom="SARES20-MF1:MOT_16", # ) -namespace.append_obj( - "MicroscopeMotorRecord", - "SARES20-CAMS142-C1", - lazy=True, - pvname_zoom="SARES20-MF1:MOT_16", - name="samplecam_microscope", - module_name="eco.microscopes", -) +#namespace.append_obj( +# "MicroscopeMotorRecord", +# "SARES20-CAMS142-C1", +# lazy=True, +# pvname_zoom="SARES20-MF1:MOT_16", +# name="samplecam_microscope", +# module_name="eco.microscopes", +#) namespace.append_obj( "CameraBasler", @@ -908,13 +908,13 @@ namespace.append_obj( module_name="eco.devices_general.cameras_swissfel", ) -namespace.append_obj( - "CameraBasler", - "SARES20-CAMS142-C3", - lazy=True, - name="samplecam_xrd", - module_name="eco.devices_general.cameras_swissfel", -) +#namespace.append_obj( +# "CameraBasler", +# "SARES20-CAMS142-C3", +# lazy=True, +# name="samplecam_xrd", +# module_name="eco.devices_general.cameras_swissfel", +#) # namespace.append_obj( # "PaseShifterAramis", @@ -1029,25 +1029,25 @@ namespace.append_obj( ) # ad hoc incoupling device -class Incoupling(Assembly): - def __init__(self, name=None): - super().__init__(name=name) - self._append( - SmaractRecord, "SARES23:LIC13", name="mirr_table_pitch", is_setting=True - ) - self._append( - SmaractRecord, "SARES23:LIC14", name="mirr_table_roll", is_setting=True - ) - # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) - # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) - # self._append(SmaractRecord, "SARES23:ESB17", name="rotation", is_setting=True) - - -namespace.append_obj( - Incoupling, - lazy=True, - name="las_inc", -) +#class Incoupling(Assembly): +# def __init__(self, name=None): +# super().__init__(name=name) +# self._append( +# SmaractRecord, "SARES23:LIC13", name="mirr_table_pitch", is_setting=True +# ) +# self._append( +# SmaractRecord, "SARES23:LIC14", name="mirr_table_roll", is_setting=True +# ) +# # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) +# # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) +# # self._append(SmaractRecord, "SARES23:ESB17", name="rotation", is_setting=True) +# +# +#namespace.append_obj( +# Incoupling, +# lazy=True, +# name="las_inc", +#) class THz_in_air(Assembly): @@ -1143,11 +1143,11 @@ class THz_in_air(Assembly): return 1.0 * val2 -namespace.append_obj( - THz_in_air, - lazy=True, - name="tia", -) +#namespace.append_obj( +# THz_in_air, +# lazy=True, +# name="tia", +#) namespace.append_obj( "SmaractController", @@ -1370,3 +1370,19 @@ namespace.init_all() # "desc": "DCM Monochromator", # "type": "eco.xoptics.dcm:Double_Crystal_Mono", # }, +def pgroup2name(pgroup): + tp = "/sf/bernina/exp/" + d = Path(tp) + dirs = [i for i in d.glob("*") if i.is_symlink()] + names = [i.name for i in dirs] + targets = [i.resolve().name for i in dirs] + return names[targets.index(pgroup)] + + +def name2pgroups(name): + tp = "/sf/bernina/exp/" + d = Path(tp) + dirs = [i for i in d.glob("*") if i.is_symlink()] + names = [i.name for i in dirs] + targets = [i.resolve().name for i in dirs] + return [[i_n, i_p] for i_n, i_p in zip(names, targets) if name in i_n] diff --git a/eco/bernina/config.py b/eco/bernina/config.py index 3e130a8..61d94b7 100755 --- a/eco/bernina/config.py +++ b/eco/bernina/config.py @@ -386,22 +386,6 @@ components = [ "bsport": 11151, }, }, - { - "args": ["SARES20-CAMS142-M1"], - "name": "cam_sample_sideview", - "z_und": 142, - "desc": "", - "type": "eco.devices_general.cameras_swissfel:CameraBasler", - "kwargs": {}, - }, - { - "args": ["SARES20-CAMS142-M3"], - "name": "cam_sample_inline", - "z_und": 142, - "desc": "", - "type": "eco.devices_general.cameras_swissfel:CameraBasler", - "kwargs": {}, - }, # { # "args": ["SARES20-CAMS142-C3"], # "name": "cam_sample_xrd", @@ -423,18 +407,6 @@ components = [ # "camera_pv": config["cams_qioptiq"]["camera_pv"], # }, # }, - { - "args": [], - "name": "cams_sigma", - "z_und": 142, - "desc": "Sigma objective", - "type": "eco.endstations.bernina_cameras:Sigma", - "kwargs": { - "bshost": "sf-daqsync-01.psi.ch", - "bsport": 11149, - "camera_pv": config["cams_sigma"]["camera_pv"], - }, - }, # { # "args": ["SLAAR02-TSPL-EPL"], # "name": "phase_shifter", diff --git a/eco/elements/adjustable.py b/eco/elements/adjustable.py index 2455548..cac51f4 100644 --- a/eco/elements/adjustable.py +++ b/eco/elements/adjustable.py @@ -168,18 +168,23 @@ class ValueInRange: def update_changes(Adj): def get_position_str(start, end, value): - start = float(start) - value = float(value) - end = float(end) - s = ValueInRange(start, end, bar_width=30, unit="", fmt="1.5g").get_str(value) - return ( - colorama.Style.BRIGHT - + f"{value:1.5}".rjust(10) - + colorama.Style.RESET_ALL - + " " - + s - + 2 * "\t" - ) + vals = [v if hasattr(v,"__iter__") else [v] for v in [start, end, value]] + bars = "" + for s, v, e in zip(*vals): + s = float(s) + v = float(v) + e = float(e) + s = ValueInRange(s, e, bar_width=30, unit="", fmt="1.5g").get_str(v) + bars = bars + ( + colorama.Style.BRIGHT + + f"{v:1.5}".rjust(10) + + colorama.Style.RESET_ALL + + " " + + s + + 2 * "\t" + + "\n" + ) + return bars def update_change(self, value, elog=None): start = self.get_current_value() diff --git a/eco/endstations/bernina_diffractometers.py b/eco/endstations/bernina_diffractometers.py index a371285..2682432 100644 --- a/eco/endstations/bernina_diffractometers.py +++ b/eco/endstations/bernina_diffractometers.py @@ -14,7 +14,7 @@ from ..elements.assembly import Assembly from ..detector.jungfrau import Jungfrau from .kappa_conversion import kappa2you, you2kappa import numpy as np - +from ..utilities.recspace import Crystals def addMotorRecordToSelf(self, name=None, Id=None): try: @@ -274,6 +274,9 @@ class GPS(Assembly): unit="deg", ) + #self._append(Crystals, diffractometer_you=self, name="crystals", is_display="recursive") + + def gui(self, guiType="xdm"): """Adjustable convention""" cmd = ["caqtdm", "-macro"] @@ -766,6 +769,7 @@ class XRDYou(Assembly): is_display=False, view_toplevel_only=True, ) + self._append(Crystals, diffractometer_you=self, name="crystals", is_setting=False, is_display=False) def get_adjustable_positions_str(self): ostr = "*****XRD motor positions******\n" diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index 93a4e69..4e9e653 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -1,7 +1,7 @@ from eco.loptics.position_monitors import CameraPositionMonitor from ..elements.assembly import Assembly from functools import partial -from ..devices_general.motors import SmaractStreamdevice, MotorRecord +from ..devices_general.motors import SmaractStreamdevice, MotorRecord, SmaractRecord from ..elements.adjustable import AdjustableMemory, AdjustableVirtual, AdjustableFS from ..epics.adjustable import AdjustablePv, AdjustablePvEnum from ..epics.detector import DetectorPvData @@ -174,27 +174,27 @@ class LaserBernina(Assembly): AdjustableVirtual, [self.wp_att], wp2uJ, uJ2wp, name="pulse_energy_pump" ) - self._append( - MotorRecord, - self.pvname + "-M522:MOTOR_1", - name="delaystage_pump", - is_setting=True, - ) - self._append( - DelayTime, self.delaystage_pump, name="delay_pump", is_setting=True - ) + #self._append( + # MotorRecord, + # self.pvname + "-M522:MOTOR_1", + # name="delaystage_pump", + # is_setting=True, + #) + #self._append( + # DelayTime, self.delaystage_pump, name="delay_pump", is_setting=True + #) self._append(XltEpics, name="xlt", is_setting=True, is_display="recursive") # Upstairs, Laser 1 LAM self._append( MotorRecord, "SLAAR21-LMOT-M521:MOTOR_1", - name="delaystage_eos", + name="delaystage_pump", is_setting=True, ) self._append( DelayTime, - self.delaystage_eos, - name="delay_eos", + self.delaystage_pump, + name="delay_pump", is_setting=True, ) # self._append( @@ -203,6 +203,12 @@ class LaserBernina(Assembly): # name="delaystage_thz", # is_setting=True, # ) + self._append( + SmaractRecord, "SARES23:ESB3", name="pump_hor", is_setting=True + ) + self._append( + SmaractRecord, "SARES23:ESB18", name="pump_ver", is_setting=True + ) class DelayTime(AdjustableVirtual): diff --git a/eco/utilities/recspace.py b/eco/utilities/recspace.py index 06a72aa..49bcf5c 100644 --- a/eco/utilities/recspace.py +++ b/eco/utilities/recspace.py @@ -4,13 +4,16 @@ from diffcalc.hkl.geometry import Position from diffcalc.ub import calc as dccalc import pandas as pd import numpy as np +from datetime import datetime +import os +from PIL import Image # from diffcalc.ub import calc calc import UBCalculation, Crystal from eco.elements.assembly import Assembly from eco.elements.adjustable import AdjustableMemory, AdjustableFS, AdjustableVirtual from typing import Tuple, Optional from eco.elements.adj_obj import AdjustableObject - +from epics import PV class CrystalNew(Assembly): def __init__(self, *args, name=None, **kwargs): @@ -35,122 +38,58 @@ class CrystalNew(Assembly): ) +class Crystals(Assembly): + def __init__(self, diffractometer_you=None, name=None): + super().__init__(name=name) + self.diffractometer = diffractometer_you + self._append(AdjustableFS, f'/photonics/home/gac-bernina/eco/configuration/crystals/{name}_list', name="crystal_list", default_value={}, is_setting=True) + for key, date in self.crystal_list().items(): + self._append(DiffGeometryYou, diffractometer_you=self.diffractometer, name=key) + def append_crystal(self, name=None): + if name==None: + name = input("Please choose a name for your crystal (no spaces or other special characters):") + specials = np.array([" ", "/", "(", ")", "[", "]"]) + in_name = np.array([s in name for s in specials]) + if np.any(in_name): + raise Exception(f"Special character(s) {specials[in_name]} in name not allowed") + self._append(DiffGeometryYou, diffractometer_you=self.diffractometer, name=name, is_setting=True, is_display=False) + crystals = self.crystal_list() + crystals[name] = str(datetime.now()) + self.crystal_list.mv(crystals) + self.__dict__[name].new_ub() + + def remove_crystal(self, name=None): + """ + Remove crystal with a given name, deletes also the files. + """ + sure = 'n' + sure = input(f"are you sure you want to permanently remove the crystal {name} and its UB matrix and memories (y/n)? ") + if sure == 'y': + crystals = self.crystal_list() + removed = crystals.pop(name) + self.crystal_list.mv(crystals) + attrs = ["unit_cell", "u_matrix", "ub_matrix", "orientations", "reflections", "constraints"] + for a in attrs: + if os.path.exists(f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_{a}"): + os.remove(f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_{a}") + class DiffGeometryYou(Assembly): def __init__(self, diffractometer_you=None, name=None): super().__init__(name=name) # self._append(diffractometer_you,call_obj=False, name='diffractometer') - self._append(AdjustableMemory, {}, name="contraints") - self._append(AdjustableMemory, {}, name="unit_cell") - self._append(AdjustableMemory, {}, name="U_matrix") - self._append(AdjustableMemory, {}, name="UB_matrix") - self._append(AdjustableMemory, [], name="orientations") - self.diffractometer = diffractometer_you - - def get_position_angles(self): - nu = self.diffractometer.nu.get_current_value() - mu = self.diffractometer.mu.get_current_value() - delta = self.diffractometer.delta.get_current_value() - eta = self.diffractometer.eta.get_current_value() - chi = self.diffractometer.chi.get_current_value() - phi = self.diffractometer.phi.get_current_value() - return mu, delta, nu, eta, chi, phi - - def set_unit_cell( - self, name_crystal, a=None, b=None, c=None, alpha=None, beta=None, gamma=None - ): - self.unit_cell.set_target_value( - { - "name": name_crystal, - "a": a, - "b": b, - "c": c, - "alpha": alpha, - "beta": beta, - "gamma": gamma, - } - ) - self.recalculate() - - def recalculate(self): - self.ubcalc = dccalc.UBCalculation("you") - uc = self.unit_cell() - self.ubcalc.set_lattice(uc.pop("name"), **uc) - for ori in self.orientations(): - self.ubcalc.add_orientation(ori.pop("hkl"), ori.pop("xyz"), **ori) - - def add_reflection( - self, - hkl, - position, - energy, - tag=None, - ): - """Add a reference reflection. - - Adds a reflection position in degrees and in the systems internal - representation. - - Parameters - ---------- - hkl : Tuple[float, float, float] - hkl index of the reflection - position: Position - list of diffractometer angles in internal representation in degrees - energy : float - energy of the x-ray beam - tag : Optional[str], default = None - identifying tag for the reflection - """ - - self.ubcalc.add_reflection(hkl, position, energy, tag=tag) - self.reflections.set_target_value( - self.reflections() - + [{"hkl": hkl, "position": position, "energy": energy, "tag": tag}] - ) - - def add_orientation(self, hkl, xyz, position=None, tag=None): - """Add a reference orientation. - - Adds a reference orientation in the diffractometer - coordinate system. - - Parameters - ---------- - hkl : :obj:`tuple` of numbers - hkl index of the reference orientation - xyz : :obj:`tuple` of numbers - xyz coordinate of the reference orientation - position: :obj:`list` or :obj:`tuple` of numbers - list of diffractometer angles in internal representation in degrees - tag : str - identifying tag for the reflection - """ - self.recalculate() - self.ubcalc.add_orientation(hkl, xyz, position=None, tag=None) - self.orientations.set_target_value( - self.orientations() - + [{"hkl": hkl, "xyz": xyz, "position": position, "tag": tag}] - ) - self.recalculate() - - def calc_ub(self, *args, **kwargs): - self.ubcalc.calc_ub(*args, **kwargs) - - def fit_ub(self, *args, **kwargs): - self.ubcalc.fit_ub(*args, **kwargs) - - pass - - -class DiffGeometryYou2(Assembly): - def __init__(self, diffractometer_you=None, name=None): - super().__init__(name=name) - # self._append(diffractometer_you,call_obj=False, name='diffractometer') - self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_unit_cell', name="unit_cell", default_value={}, is_setting=True) - self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_u_matrix', name="u_matrix", default_value=[], is_setting=True) - self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_ub_matrix', name="ub_matrix", default_value=[], is_setting=True) - self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_orientations', name="orientations", default_value=[], is_setting=True) - self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_reflections', name="reflections", default_value=[], is_setting=True) + self._append(AdjustableFS, f'/photonics/home/gac-bernina/eco/configuration/crystals/{name}_unit_cell', name="unit_cell", default_value={ + "name": name, + "a": 1, + "b": 1, + "c": 1, + "alpha": 90, + "beta": 90, + "gamma": 90, + }, is_setting=True) + self._append(AdjustableFS, f'/photonics/home/gac-bernina/eco/configuration/crystals/{name}_u_matrix', name="u_matrix", default_value=[], is_setting=True, is_display=False) + self._append(AdjustableFS, f'/photonics/home/gac-bernina/eco/configuration/crystals/{name}_ub_matrix', name="ub_matrix", default_value=[], is_setting=True, is_display=False) + self._append(AdjustableFS, f'/photonics/home/gac-bernina/eco/configuration/crystals/{name}_orientations', name="orientations", default_value=[], is_setting=True) + self._append(AdjustableFS, f'/photonics/home/gac-bernina/eco/configuration/crystals/{name}_reflections', name="reflections", default_value=[], is_setting=True) self.diffractometer = diffractometer_you cons = { 'mu': None, @@ -171,7 +110,7 @@ class DiffGeometryYou2(Assembly): 'psi': None, 'omega': None, } - self._append(AdjustableFS, f'/photonics/home/gac-bernina/temp/diffc/{name}_constraints', name="_constraints", default_value=cons, is_setting=True, is_display=False) + self._append(AdjustableFS, f'/photonics/home/gac-bernina/eco/configuration/crystals/{name}_constraints', name="_constraints", default_value=cons, is_setting=True, is_display=False) self._append(AdjustableObject, self._constraints, name="constraints", is_setting=False, is_display='recursive') @@ -186,17 +125,20 @@ class DiffGeometryYou2(Assembly): def get_h(*args, **kwargs): return self.calc_hkl()[0] def set_h(val): - return self._calc_angles_unique_diffractometer(h=val) + return self._calc_angles_unique_diffractometer([val,None,None]) def get_k(*args, **kwargs): return self.calc_hkl()[1] def set_k(val): - return self._calc_angles_unique_diffractometer(k=val) + return self._calc_angles_unique_diffractometer([None,val,None]) def get_l(*args, **kwargs): return self.calc_hkl()[2] def set_l(val): - return self._calc_angles_unique_diffractometer(l=val) + return self._calc_angles_unique_diffractometer([None,None,val]) def get_hkl(*args, **kwargs): return self.calc_hkl() + def set_hkl(val): + return self._calc_angles_unique_diffractometer(val) + self._append(AdjustableVirtual, list(self._diff_adjs.values()), get_h, set_h, name="h") self._append(AdjustableVirtual, list(self._diff_adjs.values()), get_k, set_k, name="k") @@ -222,8 +164,8 @@ class DiffGeometryYou2(Assembly): nu, mu, delta, eta, chi, phi = self.convert_to_you(**{key: adj() for key, adj in self._diff_adjs.items()}) return mu, delta, nu, eta, chi, phi - def _calc_angles_unique_diffractometer(self,h,k,l): - angles = self.calc_angles_unique(h,k,l) + def _calc_angles_unique_diffractometer(self,hkl): + angles = self.calc_angles_unique(*hkl) return self.convert_from_you(**angles) def check_target_value_within_limits(self, **kwargs): @@ -241,20 +183,21 @@ class DiffGeometryYou2(Assembly): def new_ub(self): ### missing: clear ub ### ### missing: check ub ### - crystal_name = input("Name of the crystal: ") - a = float(input("Lattice constant: ")) - b = float(input(f"Lattice constant b {(a)}: ") or a) - c = float(input(f"Lattice constant c {(a)}: ") or a) + crystal_name = input(f"Name of the crystal: ({self.name})" or self.name) + a = float(input(f"Lattice constant a ({self.unit_cell()['a']}): ") or {self.unit_cell['a']}) + b = float(input(f"Lattice constant b ({a}): ") or a) + c = float(input(f"Lattice constant c ({a}): ") or a) alpha = float(input("Angle alpha (90): ") or 90) - beta = float(input(f"Angle beta {(alpha)}: ") or alpha) - gamma = float(input(f"Angle gamma {(alpha)}: ") or alpha) - normal = [float(val) for val in input("(h,k,l) surface normal (along YOU z-axis) without brackets and ',' separated: ").split(",")] - inplane = [float(val) for val in input("(h,k,l) in-plane orientation along beam (YOU y-axis) without brackets and ',' separated: ")] + beta = float(input(f"Angle beta ({alpha}): ") or alpha) + gamma = float(input(f"Angle gamma ({alpha}): ") or alpha) + im = Image.open('/photonics/home/gac-bernina/eco/configuration/crystals/you_diffractometer.png') + normal = [float(val) for val in input("(h,k,l) surface normal (along YOU z-axis), e.g. 0,0,1: ").split(",") or [0,0,1]] + inplane = [float(val) for val in input("(h,k,l) in-plane orientation along beam (YOU y-axis), e.g. 1,0,0: ").split(",") or [1,0,0]] self.set_unit_cell(crystal_name, a, b, c, alpha, beta, gamma) - self.add_orientation(normal, (1,0,0), tag='surface normal') - self.add_orientation(inplane, (0,1,0), tag='in-plane along YOU y axis') + self.add_orientation(normal, (0,0,1), tag='surface normal') + self.add_orientation(inplane, (0,1,0), tag='in-plane along x-ray beam direction') self.calc_ub() - print("UB was calculated - next please set the constraints and the limits of the diffractometer motors") + print("UB was calculated - next please set the constraints (.constraints) and the limits of the diffractometer motors") def set_unit_cell( self, name_crystal, a=None, b=None, c=None, alpha=None, beta=None, gamma=None @@ -274,21 +217,17 @@ class DiffGeometryYou2(Assembly): def recalculate(self): self.ubcalc = dccalc.UBCalculation("you") + #self.ubcalc.n_phi = [0,0,1] uc = self.unit_cell() self.ubcalc.set_lattice(uc.pop("name"), **uc) for ori in self.orientations(): self.ubcalc.add_orientation(ori.pop("hkl"), ori.pop("xyz"), **ori) for refl in self.reflections(): - self.ubcalc.add_reflection(refl.pop("hkl"), refl.pop("xyz"), **refl) + self.ubcalc.add_reflection(refl.pop("hkl"), **refl) self._u_ub_to_dc() - def add_reflection( - self, - hkl, - position, - energy, - tag=None, - ): + + def add_reflection(self, hkl, mu=None, delta=None, nu=None, eta=None, chi=None, phi=None, energy=None, tag=None,): """Add a reference reflection. Adds a reflection position in degrees and in the systems internal @@ -298,20 +237,40 @@ class DiffGeometryYou2(Assembly): ---------- hkl : Tuple[float, float, float] hkl index of the reflection - position: Position - list of diffractometer angles in internal representation in degrees + mu, delta, nu, eta, chi, phi: float + diffractometer angles in degrees, if not given, the current diffractometer angles are used energy : float - energy of the x-ray beam + energy of the x-ray beam, if not given, the mono or machine energy are used depending on the beamline mode tag : Optional[str], default = None identifying tag for the reflection """ - + setvals = [mu, delta, nu, eta, chi, phi] + curvals = self.get_diffractometer_angles() + angs = [curval if setval == None else setval for setval, curval in zip(setvals, curvals)] + if energy is None: + energy = self.get_energy() self.ubcalc.add_reflection(hkl, position, energy, tag=tag) self.reflections.set_target_value( self.reflections() + [{"hkl": hkl, "position": position, "energy": energy, "tag": tag}] ) + def del_reflection(self, idx): + """Delete a reference reflection. + + Parameters + ---------- + idx : int + index of the deleted reflection + """ + self.hklcalc.del_reflection(idx) + refls = self.reflections() + removed = refls.pop(idx) + self.reflections.set_target_value(refls) + print(f"Removed reflection {removed}") + self.recalculate() + + def add_orientation(self, hkl, xyz, position=None, tag=None): """Add a reference orientation. @@ -335,6 +294,21 @@ class DiffGeometryYou2(Assembly): ) self.recalculate() + def del_orientation(self, idx): + """Delete a reference reflection. + + Parameters + ---------- + idx : int + index of the deleted reflection + """ + refls = self.orientations() + removed = refls.pop(idx) + self.orientations.set_target_value(refls) + print(f"Removed reflection {removed}") + self.recalculate() + + def calc_ub(self, idx1=None, idx2=None): """Calculate UB matrix. @@ -356,6 +330,10 @@ class DiffGeometryYou2(Assembly): self.ubcalc.calc_ub(idx1, idx2) self._u_ub_from_dc() + def show_you_geometry(self): + im = Image.open('/photonics/home/gac-bernina/eco/configuration/crystals/you_diffractometer.png') + im.show() + def fit_ub(self, refine_lattice=False, refine_umatrix=False): """Refine UB matrix using reference reflections. @@ -382,7 +360,7 @@ class DiffGeometryYou2(Assembly): def calc_angles(self, h=None,k=None,l=None, energy=None): """calculate diffractometer angles for a given h,k,l and energy in eV. If any of the h, k, l are not given, their current value is used instead. - If the energy is not given, the monochromator energy is used + energy: float energy of the x-ray beam, if not given, the mono or machine energy are used depending on the beamline mode Shows all solutions neglecting diffractometer limits""" setvals = [h,k,l] curvals = [self.h, self.k, self.l] @@ -391,7 +369,7 @@ class DiffGeometryYou2(Assembly): cons = Constraints(self._constraints()) hklcalc = HklCalculation(self.ubcalc, cons) if energy is None: - energy = 8000 + energy = self.get_energy() lam = self.en2lam(energy) result = hklcalc.get_position(h,k,l,lam) result = pd.concat([pd.DataFrame.from_dict({**tres[0].asdict,**tres[1]},orient='index', columns=[f'sol. {n}']) for n,tres in enumerate(result)],axis=1) @@ -410,7 +388,7 @@ class DiffGeometryYou2(Assembly): print(f"There is not a unique angular configuration to reach ({h},{k},{l}), please change the diffractometer motor soft limits to allow only one of the solutions shown below:") print(df.loc[idx_in]) raise Exception("No unique solution") - elif idx_in ==0: + elif len(idx_in) ==0: print("There is no angular configuration, which is allowed for the current diffractometer motor soft limits. please check the diffractometer limits.") print("Solutions") print(df) @@ -430,7 +408,7 @@ class DiffGeometryYou2(Assembly): pos = Position(*angs) self.recalculate() if energy is None: - energy = 8000 + energy = self.get_energy() lam = self.en2lam(energy) cons = Constraints(self._constraints()) hklcalc = HklCalculation(self.ubcalc, cons) @@ -441,6 +419,11 @@ class DiffGeometryYou2(Assembly): return return hkl + def get_energy(self): + energy = PV("SAROP21-ARAMIS:ENERGY").value + return energy + + def _u_ub_from_dc(self): self.ub_matrix(self.ubcalc.UB.tolist()) self.u_matrix(self.ubcalc.U.tolist()) From a471bc6a46171b1c6da058159f632cf4e99601c1 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Mon, 11 Jul 2022 13:18:47 +0200 Subject: [PATCH 06/52] fixes --- eco/bernina/config.py | 16 +++++----- eco/elements/adjustable.py | 16 ++++++++-- eco/utilities/recspace.py | 12 ++++--- eco/xoptics/pulse_picker.py | 64 +++++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 16 deletions(-) create mode 100755 eco/xoptics/pulse_picker.py diff --git a/eco/bernina/config.py b/eco/bernina/config.py index 61d94b7..8f020cb 100755 --- a/eco/bernina/config.py +++ b/eco/bernina/config.py @@ -287,14 +287,14 @@ components = [ "desc": "Slits behind attenuator", "type": "eco.xoptics.slits:SlitPosWidth", }, - { - "name": "det_dio", - "args": ["SAROP21-PDIO138"], - "z_und": 138, - "desc": "Diode digitizer for exp data", - "type": "eco.devices_general.detectors:DiodeDigitizer", - "kwargs": {"VME_crate": "SAROP21-CVME-PBPS2", "link": 9}, - }, + # { + # "name": "det_dio", + # "args": ["SAROP21-PDIO138"], + # "z_und": 138, + # "desc": "Diode digitizer for exp data", + # "type": "eco.devices_general.detectors:DiodeDigitizer", + # "kwargs": {"VME_crate": "SAROP21-CVME-PBPS2", "link": 9}, + # }, { "name": "prof_att", "args": ["SAROP21-PPRM138"] * 2, diff --git a/eco/elements/adjustable.py b/eco/elements/adjustable.py index cac51f4..6d1ad5c 100644 --- a/eco/elements/adjustable.py +++ b/eco/elements/adjustable.py @@ -169,6 +169,7 @@ class ValueInRange: def update_changes(Adj): def get_position_str(start, end, value): vals = [v if hasattr(v,"__iter__") else [v] for v in [start, end, value]] +# bars = [] bars = "" for s, v, e in zip(*vals): s = float(s) @@ -182,8 +183,15 @@ def update_changes(Adj): + " " + s + 2 * "\t" - + "\n" ) +# bars.append(( +# colorama.Style.BRIGHT +# + f"{v:1.5}".rjust(10) +# + colorama.Style.RESET_ALL +# + " " +# + s +# + 2 * "\t" +# )) return bars def update_change(self, value, elog=None): @@ -194,14 +202,16 @@ def update_changes(Adj): ) except TypeError: print(f"Changing {self.name} from {start} to {value}") - + #for pos in get_position_str(start, value, start): + # print(pos, end="\r") print(get_position_str(start, value, start), end="\r") try: if hasattr(self, "add_value_callback"): def cbfoo(**kwargs): present_value = self.get_current_value() - # print(get_position_str(start, value, kwargs["value"]), end="\r") + #for pos in get_position_str(start, value, present_value): + # print(pos, end="\r") print(get_position_str(start, value, present_value), end="\r") cb_id = self.add_value_callback(cbfoo) diff --git a/eco/utilities/recspace.py b/eco/utilities/recspace.py index 49bcf5c..266420f 100644 --- a/eco/utilities/recspace.py +++ b/eco/utilities/recspace.py @@ -223,7 +223,8 @@ class DiffGeometryYou(Assembly): for ori in self.orientations(): self.ubcalc.add_orientation(ori.pop("hkl"), ori.pop("xyz"), **ori) for refl in self.reflections(): - self.ubcalc.add_reflection(refl.pop("hkl"), **refl) + position = Position(*refl.pop("position")) + self.ubcalc.add_reflection(refl.pop("hkl"), position, refl.pop("energy"), **refl) self._u_ub_to_dc() @@ -249,10 +250,11 @@ class DiffGeometryYou(Assembly): angs = [curval if setval == None else setval for setval, curval in zip(setvals, curvals)] if energy is None: energy = self.get_energy() + position = Position(*angs) self.ubcalc.add_reflection(hkl, position, energy, tag=tag) self.reflections.set_target_value( self.reflections() - + [{"hkl": hkl, "position": position, "energy": energy, "tag": tag}] + + [{"hkl": hkl, "position": angs, "energy": energy, "tag": tag}] ) def del_reflection(self, idx): @@ -263,7 +265,7 @@ class DiffGeometryYou(Assembly): idx : int index of the deleted reflection """ - self.hklcalc.del_reflection(idx) + self.ubcalc.del_reflection(idx) refls = self.reflections() removed = refls.pop(idx) self.reflections.set_target_value(refls) @@ -334,7 +336,7 @@ class DiffGeometryYou(Assembly): im = Image.open('/photonics/home/gac-bernina/eco/configuration/crystals/you_diffractometer.png') im.show() - def fit_ub(self, refine_lattice=False, refine_umatrix=False): + def fit_ub(self, indices, refine_lattice=False, refine_umatrix=False): """Refine UB matrix using reference reflections. Parameters @@ -352,7 +354,7 @@ class DiffGeometryYou(Assembly): Refined U matrix as NumPy array and refined crystal lattice parameters. """ self.recalculate() - self.ubcalc.fit_ub( refine_lattice, refine_umatrix) + self.ubcalc.fit_ub(indices, refine_lattice=refine_lattice, refine_umatrix=refine_umatrix) self._u_ub_from_dc() if refine_lattice: self._lat_from_dc() diff --git a/eco/xoptics/pulse_picker.py b/eco/xoptics/pulse_picker.py new file mode 100755 index 0000000..25b1094 --- /dev/null +++ b/eco/xoptics/pulse_picker.py @@ -0,0 +1,64 @@ +from epics import PV +from ..devices_general.utilities import Changer +from time import sleep +import numpy as np +from ..devices_general.motors import MotorRecord + +from ..aliases import Alias + + +def addMotorRecordToSelf(self, name=None, Id=None): + try: + self.__dict__[name] = MotorRecord(Id, name=name) + self.alias.append(self.__dict__[name].alias) + except: + print(f"Warning! Could not find motor {name} (Id:{Id})") + + +class PulsePickerSwissfel(Assembly): + def __init__(self, Id=None, evronoff=None, evrsrc=None, name=None): + self.name = name + self.alias = Alias(name) + self.evrsrc = evrsrc + self.evronoff = evronoff + + self.Id = Id + self._openclose = PV(self.evronoff) + self._evrsrc = PV(self.evrsrc) + addMotorRecordToSelf(self, Id=self.Id + ":MOTOR_X1", name="x") + addMotorRecordToSelf(self, Id=self.Id + ":MOTOR_Y1", name="y") + + def movein(self): + self.x.set_target_value(4.45) + self.y.set_target_value(-1.75) + + def moveout(self): + self.x.set_target_value(-5) + self.y.set_target_value(-1.75) + + def open(self): + self._openclose.put(1) + self._evrsrc.put(62) + print("Opened Pulse Picker") + + def close(self): + self._openclose.put(0) + self._evrsrc.put(62) + print("Closed Pulse Picker") + + def trigger(self): + self._openclose.put(1) + self._evrsrc.put(0) + print("Set Pulse Picker to trigger (src 0 and output On)") + + def get_status(self): + stat = self._evrsrc.get() + if stat == 62 and self._openclose.get() == 1: + return "open" + if self._openclose.get() == 0: + return "closed" + else: + return "unknown" + + def __repr__(self): + return f"FEL pulse picker state {self.get_status()}." From ec565f6cbe94d09cd3e26f1fc738f99626e5ed39 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Tue, 12 Jul 2022 10:43:40 +0200 Subject: [PATCH 07/52] fixed att_usd opening the pulse picker before transl2 finished moving --- eco/bernina/bernina.py | 2 +- eco/bernina/config.py | 11 ----------- eco/utilities/runtable.py | 35 +++++++++++++++++++++++++---------- eco/xoptics/att_usd.py | 2 +- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 400fab8..9e7115a 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -1335,7 +1335,7 @@ except: # namespace.append_obj("Xom", module_name="xom", name="xom", lazy=True) -namespace.init_all() +#namespace.init_all() ############## maybe to be recycled ################### diff --git a/eco/bernina/config.py b/eco/bernina/config.py index 8f020cb..59cd577 100755 --- a/eco/bernina/config.py +++ b/eco/bernina/config.py @@ -354,17 +354,6 @@ components = [ # "diff_detector": {"jf_id": "JF01T03V01"}, # }, # }, - { - "args": [], - "name": "vonHamos", - "z_und": 142, - "desc": "Kern experiment, von Hamos vertical and horizontal stages ", - "type": "eco.devices_general.micos_stage:stage", - "kwargs": { - "vonHamos_horiz_pv": config["Kern"]["vonHamos_horiz"], - "vonHamos_vert_pv": config["Kern"]["vonHamos_vert"], - }, - }, # { # "args": [], # "name": "gasjet", diff --git a/eco/utilities/runtable.py b/eco/utilities/runtable.py index 0f190d0..eaef117 100644 --- a/eco/utilities/runtable.py +++ b/eco/utilities/runtable.py @@ -545,8 +545,14 @@ class Run_Table: for s in self._parse_exclude_class_types ] ), + ~np.any( + [ + key in s for s in parent_name.split(".") + ] + ), ] ): + print(key) sub_classes.append(s_class) return set(sub_classes).union( [ @@ -558,7 +564,7 @@ class Run_Table: ] ) - def _parse_parent_fewerparents(self, parent=None): + def _parse_parent_fewerparents(self, parent=None, verbose=False): if parent == None: parent = self.devices for key in parent.__dict__.keys(): @@ -580,6 +586,8 @@ class Run_Table: ] ): self.adjustables[s_class.name] = {} + if verbose: + print(key) self._parse_child_instances_fewerparents(s_class) except Exception as e: print(e) @@ -589,6 +597,8 @@ class Run_Table: self.adjustables[f"env_{name}"] = { key: PvRecord(pvsetname=ch) for key, ch in value.items() } + if verbose: + print("Done parsing, checking adjustables") self._check_adjustables() def _parse_child_instances(self, parent_class, pp_name=None): @@ -1062,7 +1072,7 @@ class Run_Table_DataFrame(DataFrame): self._parse_exclude_keys = "status_indicators settings_collection status_indicators_collection presets memory _elog _currentChange _flags __ alias namespace daq scan MasterEventSystem _motor Alias".split( " " ) - self._parse_exclude_class_types = "__ alias namespace daq scan MasterEventSystem _motor Alias AdjustablePv".split( + self._parse_exclude_class_types = "__ alias namespace daq scan MasterEventSystem _motor Alias AdjustablePv Collection".split( " " ) self._adj_exclude_class_types = ( @@ -1229,7 +1239,7 @@ class Run_Table_DataFrame(DataFrame): self.adjustables[name][".".join([name, "self"])] = device def _get_all_adjustables_fewerparents( - self, device, adj_prefix=None, parent_name=None + self, device, adj_prefix=None, parent_name=None, verbose=False ): if adj_prefix is not None: name = ".".join([adj_prefix, device.name]) @@ -1252,6 +1262,8 @@ class Run_Table_DataFrame(DataFrame): if parent_name == device.name: self.adjustables[parent_name][key] = value else: + #print("GET ADJ", parent_name, name, key) + self.adjustables[parent_name][".".join([name, key])] = value if parent_name == device.name: @@ -1259,17 +1271,18 @@ class Run_Table_DataFrame(DataFrame): self.adjustables[parent_name]["self"] = device def _parse_child_instances_fewerparents( - self, parent_class, adj_prefix=None, parent_name=None + self, parent_class, adj_prefix=None, parent_name=None, verbose=False ): if parent_name is None: parent_name = own_name - self._get_all_adjustables_fewerparents(parent_class, adj_prefix, parent_name) + self._get_all_adjustables_fewerparents(parent_class, adj_prefix, parent_name, verbose=verbose) if parent_name is not parent_class.name: if adj_prefix is not None: adj_prefix = ".".join([adj_prefix, parent_class.name]) else: adj_prefix = parent_class.name + sub_classes = [] sub_classnames = [] for key in parent_class.__dict__.keys(): @@ -1288,11 +1301,13 @@ class Run_Table_DataFrame(DataFrame): for s in self._parse_exclude_class_types ] ), + ] ): - if s_class.name == None: - s_class.name = key - sub_classes.append(s_class) + if adj_prefix is None or ~np.any([key == s for s in ".".join([parent_name,adj_prefix]).split(".")]): + if s_class.name == None: + s_class.name = key + sub_classes.append(s_class) return set(sub_classes).union( [ s @@ -1303,7 +1318,7 @@ class Run_Table_DataFrame(DataFrame): ] ) - def _parse_parent_fewerparents(self, parent=None): + def _parse_parent_fewerparents(self, parent=None, verbose=False): if parent == None: parent = self.devices for key in parent.__dict__.keys(): @@ -1326,7 +1341,7 @@ class Run_Table_DataFrame(DataFrame): ): self.adjustables[key] = {} self._parse_child_instances_fewerparents( - s_class, parent_name=key + s_class, parent_name=key, verbose=verbose ) except Exception as e: print(e) diff --git a/eco/xoptics/att_usd.py b/eco/xoptics/att_usd.py index de24252..a66fcfe 100644 --- a/eco/xoptics/att_usd.py +++ b/eco/xoptics/att_usd.py @@ -339,7 +339,7 @@ class Att_usd(Assembly): self.transl_2.set_target_value(p2) print(f"Set transmission to {t:0.2E} | Moving to pos {[p1, p2]}") while (abs(p1 - self.transl_1.get_current_value()) > 0.05) or ( - abs(p2 - self.transl_2.get_current_value() > 0.05) + (abs(p2 - self.transl_2.get_current_value()) > 0.05) ): sleep(0.1) print("transmission changed") From f09f36f721a525a360a6fa824bc18ce2cc15e382 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Tue, 9 Aug 2022 10:53:24 +0200 Subject: [PATCH 08/52] shutdown work --- .vscode/settings.json | 2 +- eco/bernina/bernina.py | 38 +-- eco/detector/jungfrau.py | 46 ++++ eco/elements/protocols.py | 1 + eco/utilities/recspace.py | 39 +++ eco/utilities/runtable.py | 17 +- eco/xdiagnostics/intensity_monitors.py | 314 +++++++++++++++++-------- eco/xoptics/att_usd.py | 5 +- eco/xoptics/attenuator_aramis.py | 5 +- eco/xoptics/kb_bernina.py | 107 +-------- eco/xoptics/reflaser.py | 42 ++-- eco/xoptics/reflaser_new.py | 75 ------ 12 files changed, 364 insertions(+), 327 deletions(-) mode change 100755 => 100644 eco/xoptics/reflaser.py delete mode 100644 eco/xoptics/reflaser_new.py diff --git a/.vscode/settings.json b/.vscode/settings.json index 70697c9..fcb1936 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { "python.linting.pylintEnabled": true, "python.linting.enabled": true, - "python.pythonPath": "/sf/bernina/anaconda/bernina_envs/bernina37/bin/python" + "python.pythonPath": "/sf/bernina/applications/bm/envs/bernina38/bin/python" } \ No newline at end of file diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 9e7115a..4e08205 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -120,12 +120,12 @@ namespace.append_obj( name="slit_switch", module_name="eco.xoptics.slits", ) -namespace.append_obj( - "SlitBlades", - "SAROP21-OAPU102", - name="slit_mono", - module_name="eco.xoptics.slits", -) +# namespace.append_obj( +# "SlitBlades", +# "SAROP21-OAPU102", +# name="slit_mono", +# module_name="eco.xoptics.slits", +# ) from eco.devices_general.motors import SmaractStreamdevice, SmaractRecord @@ -245,7 +245,7 @@ namespace.append_obj( namespace.append_obj( "RefLaser_Aramis", "SAROP21-OLAS136", - module_name="eco.xoptics.reflaser_new", + module_name="eco.xoptics.reflaser", name="reflaser", lazy=True, ) @@ -485,13 +485,14 @@ namespace.append_obj( lazy=True, ) namespace.append_obj( - "KBMirrorBernina_new", + "KBMirrorBernina", "SAROP21-OKBV139", "SAROP21-OKBH140", module_name="eco.xoptics.kb_bernina", usd_table=usd_table, name="kb", diffractometer=xrd, + lazy=True, ) ### channelsfor daq ### @@ -543,6 +544,7 @@ namespace.append_obj( name="att_usd", module_name="eco.xoptics.att_usd", xp=xp, + lazy=True, ) @@ -891,14 +893,14 @@ namespace.append_obj( # pvname_zoom="SARES20-MF1:MOT_16", # ) -#namespace.append_obj( +# namespace.append_obj( # "MicroscopeMotorRecord", # "SARES20-CAMS142-C1", # lazy=True, # pvname_zoom="SARES20-MF1:MOT_16", # name="samplecam_microscope", # module_name="eco.microscopes", -#) +# ) namespace.append_obj( "CameraBasler", @@ -908,13 +910,13 @@ namespace.append_obj( module_name="eco.devices_general.cameras_swissfel", ) -#namespace.append_obj( +# namespace.append_obj( # "CameraBasler", # "SARES20-CAMS142-C3", # lazy=True, # name="samplecam_xrd", # module_name="eco.devices_general.cameras_swissfel", -#) +# ) # namespace.append_obj( # "PaseShifterAramis", @@ -1029,7 +1031,7 @@ namespace.append_obj( ) # ad hoc incoupling device -#class Incoupling(Assembly): +# class Incoupling(Assembly): # def __init__(self, name=None): # super().__init__(name=name) # self._append( @@ -1043,11 +1045,11 @@ namespace.append_obj( # # self._append(SmaractRecord, "SARES23:ESB17", name="rotation", is_setting=True) # # -#namespace.append_obj( +# namespace.append_obj( # Incoupling, # lazy=True, # name="las_inc", -#) +# ) class THz_in_air(Assembly): @@ -1143,11 +1145,11 @@ class THz_in_air(Assembly): return 1.0 * val2 -#namespace.append_obj( +# namespace.append_obj( # THz_in_air, # lazy=True, # name="tia", -#) +# ) namespace.append_obj( "SmaractController", @@ -1335,7 +1337,7 @@ except: # namespace.append_obj("Xom", module_name="xom", name="xom", lazy=True) -#namespace.init_all() +# namespace.init_all() ############## maybe to be recycled ################### diff --git a/eco/detector/jungfrau.py b/eco/detector/jungfrau.py index 4a8379e..37782ee 100644 --- a/eco/detector/jungfrau.py +++ b/eco/detector/jungfrau.py @@ -15,12 +15,14 @@ class Jungfrau(Assembly): pv_trigger="SAR-CVME-TIFALL5-EVG0:SoftEvt-EvtCode-SP", trigger_on=254, trigger_off=255, + broker_address="http://sf-daq:10002", name=None, ): super().__init__(name=name) self.alias = Alias(name, channel=jf_id, channeltype="JF") self.jf_id = jf_id + self.broker_address = broker_address self._append( AdjustablePv, pv_trigger, @@ -77,3 +79,47 @@ class Jungfrau(Assembly): filelist = list(searchpath.glob("*.h5")) times = [datetime.strptime(f.stem, "%Y%m%d_%H%M%S") for f in filelist] return filelist[times.index(max(times))].as_posix() + + def get_detector_frequency(self): + return self._event_master.event_codes[ + self._detectors_event_code + ].frequency.get_current_value() + + def get_availability(self): + is_available = ( + self.jf_id + in requests.get(f"{self.broker_address}/get_allowed_detectors_list").json()[ + "detectors" + ] + ) + return is_available + + def get_isrunning(self): + is_running = ( + self.jf_id + in requests.get(f"{self.broker_address}/get_running_detectors_list").json()[ + "detectors" + ] + ) + return is_running + + def power_on(self): + JF_channel = self.jf_id + par = {"detector_name": JF_channel} + return requests.post( + f"{self.broker_address}/power_on_detector", json=par + ).json() + + # def take_pedestal(self, JF_list=None, pgroup=None): + # if pgroup is None: + # pgroup = self.pgroup + # if not JF_list: + # JF_list = self.get_JFs_running() + # parameters = { + # "pgroup": pgroup, + # "rate_multiplicator": 1, + # "detectors": {tJF: {} for tJF in JF_list}, + # } + # return requests.post( + # f"{self.broker_address}/take_pedestal", json=parameters + # ).json() diff --git a/eco/elements/protocols.py b/eco/elements/protocols.py index 196be7a..1da8bf0 100644 --- a/eco/elements/protocols.py +++ b/eco/elements/protocols.py @@ -9,6 +9,7 @@ class Adjustable(Protocol): def set_target_value(self, value): ... + # def set_target_value(self,value) -> Changer:... diff --git a/eco/utilities/recspace.py b/eco/utilities/recspace.py index 266420f..df2c3ca 100644 --- a/eco/utilities/recspace.py +++ b/eco/utilities/recspace.py @@ -336,6 +336,45 @@ class DiffGeometryYou(Assembly): im = Image.open('/photonics/home/gac-bernina/eco/configuration/crystals/you_diffractometer.png') im.show() + def refine_ub(self, hkl, mu=None, delta=None, nu=None, eta=None, chi=None, phi=None, energy=None, refine_lattice=False, refine_umatrix=False): + """ + Refine UB matrix to using single reflection. + + Refine UB matrix to match diffractometer position for the specified + reflection. Refined U matrix will be accurate up to an azimuthal rotation + around the specified scattering vector. + + Parameters + ---------- + hkl: Tuple[float, float, float] Miller indices of the reflection. + pos: Position Diffractometer position object. + wavelength: float Radiation wavelength. + refine_lattice: Optional[bool], default = False + + Apply refined lattice parameters to the current UB calculation object. + refine_umatrix: Optional[bool], default = False + Apply refined U matrix to the current UB calculation object. + + Returns + ------- + Tuple[np.ndarray, Tuple[str, float, float, float, float, float, float]] + Refined U matrix as NumPy array and refined crystal lattice parameters. + + """ + setvals = [mu, delta, nu, eta, chi, phi] + curvals = self.get_diffractometer_angles() + angs = [curval if setval == None else setval for setval, curval in zip(setvals, curvals)] + if energy is None: + energy = self.get_energy() + wl = self.en2lam(energy) + position = Position(*angs) + self.recalculate() + self.ubcalc.refine_ub(hkl, position=position, wavelength=wl, refine_lattice=refine_lattice, refine_umatrix=refine_umatrix) + self._u_ub_from_dc() + if refine_lattice: + print("not implemented") + #self._lat_from_dc() + def fit_ub(self, indices, refine_lattice=False, refine_umatrix=False): """Refine UB matrix using reference reflections. diff --git a/eco/utilities/runtable.py b/eco/utilities/runtable.py index eaef117..15f37c2 100644 --- a/eco/utilities/runtable.py +++ b/eco/utilities/runtable.py @@ -1003,11 +1003,18 @@ class Run_Table2: ): if keys is None: keys = self._google_sheet_api.gsheet_keys() - dfs = [ - self.__dict__[key].to_dataframe() - for key in keys.split(" ") - if key in self.__dir__() - ] + dfs = [] + for key in keys.split(" "): + d = self + add = True + for k in key.split("."): + if k in d.__dict__.keys(): + d = d.__dict__[k] + else: + add = False + if all([hasattr(d, "to_dataframe"), add]): + dfs.append(d.to_dataframe()) + dfc = self._concatenate_dfs(dfs) return dfc diff --git a/eco/xdiagnostics/intensity_monitors.py b/eco/xdiagnostics/intensity_monitors.py index 59722e2..bd0eed0 100755 --- a/eco/xdiagnostics/intensity_monitors.py +++ b/eco/xdiagnostics/intensity_monitors.py @@ -50,6 +50,218 @@ class FeDigitiza(Assembly): # ] +class SolidTargetDetectorPBPS(Assembly): + def __init__( + self, + pvname, + # VME_crate=None, + # pipeline=None, + # link=None, + # channels={}, + # ch_up=12, + # ch_down=13, + # ch_left=15, + # ch_right=14, + # elog=None, + # name=None, + # calc=None, + # calc_calib={}, + ): + super().__init__(name=name) + self.pvname = pvname + self._append( + MotorRecord, pvname + ":MOTOR_X1", name="x_diodes", is_setting=True + ) + self._append( + MotorRecord, pvname + ":MOTOR_Y1", name="y_diodes", is_setting=True + ) + self._append( + MotorRecord, pvname + ":MOTOR_PROBE", name="target_y", is_setting=True + ) + self._append( + AdjustablePvEnum, pvname + ":PROBE_SP", name="target", is_setting=True + ) + + self._append( + DetectorPvDataStream, + pvname + ":INTENSITY", + name="intensity", + is_setting=False, + ) + self._append( + DetectorPvDataStream, pvname + ":XPOS", name="xpos", is_setting=False + ) + self._append( + DetectorPvDataStream, pvname + ":YPOS", name="ypos", is_setting=False + ) + + # if VME_crate: + # self.diode_up = FeDigitizer("%s:Lnk%dCh%d" % (VME_crate, link, ch_up)) + # self.diode_down = FeDigitizer("%s:Lnk%dCh%d" % (VME_crate, link, ch_down)) + # self.diode_left = FeDigitizer("%s:Lnk%dCh%d" % (VME_crate, link, ch_left)) + # self.diode_right = FeDigitizer("%s:Lnk%dCh%d" % (VME_crate, link, ch_right)) + + # if channels: + # self._append( + # DetectorPvDataStream, channels["up"], name="signal_up", is_setting=False + # ) + # self._append( + # DetectorPvDataStream, + # channels["down"], + # name="signal_down", + # is_setting=False, + # ) + # self._append( + # DetectorPvDataStream, + # channels["left"], + # name="signal_left", + # is_setting=False, + # ) + # self._append( + # DetectorPvDataStream, + # channels["right"], + # name="signal_right", + # is_setting=False, + # ) + + # if calc: + # self._append( + # DetectorPvDataStream, calc["itot"], name="intensity", is_setting=False + # ) + # self._append( + # DetectorPvDataStream, calc["xpos"], name="xpos", is_setting=False + # ) + # self._append( + # DetectorPvDataStream, calc["ypos"], name="ypos", is_setting=False + # ) + + def get_calibration_values(self, seconds=5): + self.x_diodes.set_target_value(0).wait() + self.y_diodes.set_target_value(0).wait() + ds = [self.signal_up, self.signal_down, self.signal_left, self.signal_right] + aqs = [d.acquire(seconds=seconds) for d in ds] + data = [aq.wait() for aq in aqs] + mean = [np.mean(td) for td in data] + std = [np.std(td) for td in data] + norm_diodes = [1 / tm / 4 for tm in mean] + return norm_diodes + + def set_calibration_values(self, norm_diodes): + # this is now only for bernina when using the ioxos from sla + channels = [ + "SLAAR21-LTIM01-EVR0:CALCI.INPG", + "SLAAR21-LTIM01-EVR0:CALCI.INPH", + "SLAAR21-LTIM01-EVR0:CALCI.INPE", + "SLAAR21-LTIM01-EVR0:CALCI.INPF", + ] + for tc, tv in zip(channels, norm_diodes): + PV(tc).put(bytes(str(tv), "utf8")) + channels = ["SLAAR21-LTIM01-EVR0:CALCX.INPE", "SLAAR21-LTIM01-EVR0:CALCX.INPF"] + for tc, tv in zip(channels, norm_diodes[2:4]): + PV(tc).put(bytes(str(tv), "utf8")) + channels = ["SLAAR21-LTIM01-EVR0:CALCY.INPE", "SLAAR21-LTIM01-EVR0:CALCY.INPF"] + for tc, tv in zip(channels, norm_diodes[0:2]): + PV(tc).put(bytes(str(tv), "utf8")) + + def get_calibration_values_position( + self, calib_intensities, seconds=5, motion_range=0.2 + ): + self.x_diodes.set_limits(-motion_range / 2 - 0.1, +motion_range / 2 + 0.1) + self.y_diodes.set_limits(-motion_range / 2 - 0.1, +motion_range / 2 + 0.1) + self.x_diodes.set_target_value(0).wait() + self.y_diodes.set_target_value(0).wait() + raw = [] + for pos in [motion_range / 2, -motion_range / 2]: + print(pos) + self.x_diodes.set_target_value(pos).wait() + aqs = [ + ts.acquire(seconds=seconds) + for ts in [self.signal_left, self.signal_right] + ] + vals = [ + np.mean(aq.wait()) * calib + for aq, calib in zip(aqs, calib_intensities[0:2]) + ] + raw.append((vals[0] - vals[1]) / (vals[0] + vals[1])) + grad = motion_range / np.diff(raw)[0] + # xcalib = [np.diff(calib_intensities[0:2])[0]/np.sum(calib_intensities[0:2]), grad] + xcalib = [0, grad] + self.x_diodes.set_target_value(0).wait() + raw = [] + for pos in [motion_range / 2, -motion_range / 2]: + self.y_diodes.set_target_value(pos).wait() + aqs = [ + ts.acquire(seconds=seconds) for ts in [self.signal_up, self.signal_down] + ] + vals = [ + np.mean(aq.wait()) * calib + for aq, calib in zip(aqs, calib_intensities[2:4]) + ] + raw.append((vals[0] - vals[1]) / (vals[0] + vals[1])) + grad = motion_range / np.diff(raw)[0] + # ycalib = [np.diff(calib_intensities[2:4])[0]/np.sum(calib_intensities[2:4]), grad] + ycalib = [0, grad] + self.y_diodes.set_target_value(0).wait() + return xcalib, ycalib + + def set_calibration_values_position(self, xcalib, ycalib): + channels = ["SLAAR21-LTIM01-EVR0:CALCX.INPJ", "SLAAR21-LTIM01-EVR0:CALCX.INPI"] + # txcalib = [-1*xcalib[0],-1*xcalib[1]] + for tc, tv in zip(channels, xcalib): + PV(tc).put(bytes(str(tv), "utf8")) + channels = ["SLAAR21-LTIM01-EVR0:CALCY.INPJ", "SLAAR21-LTIM01-EVR0:CALCY.INPI"] + for tc, tv in zip(channels, ycalib): + PV(tc).put(bytes(str(tv), "utf8")) + + def calibrate(self, seconds=5): + c = self.get_calibration_values(seconds=seconds) + self.set_calibration_values(c) + xc, yc = self.get_calibration_values_position(c, seconds=seconds) + self.set_calibration_values_position(xc, yc) + + def set_gains(self, value): + try: + self.diode_up.gain.set(value) + self.diode_down.gain.set(value) + self.diode_left.gain.set(value) + self.diode_right.gain.set(value) + except: + print("No diodes configured, can not change any gain!") + + def get_available_gains(self): + try: + nu = self.diode_up.gain.names + nd = self.diode_down.gain.names + nl = self.diode_left.gain.names + nr = self.diode_right.gain.names + assert ( + nu == nd == nl == nr + ), "NB: the gain options of the four diodes are not equal!!!" + return nu + except: + print("No diodes configured, can not change any gain!") + + def get_gains(self): + try: + gains = dict() + gains["up"] = (self.diode_up.gain.get_name(), self.diode_up.gain.get()) + gains["down"] = ( + self.diode_down.gain.get_name(), + self.diode_down.gain.get(), + ) + gains["left"] = ( + self.diode_left.gain.get_name(), + self.diode_left.gain.get(), + ) + gains["right"] = ( + self.diode_right.gain.get_name(), + self.diode_right.gain.get(), + ) + return gains + except: + print("No diodes configured, can not change any gain!") + + class SolidTargetDetectorPBPS_assi(Assembly): def __init__( self, @@ -340,108 +552,6 @@ class SolidTargetDetectorPBPS_new: # SAROP21-CVME-PBPS:Lnk10Ch15-WD-gain -class SolidTargetDetectorPBPS: - def __init__( - self, - Id, - VME_crate=None, - link=None, - ch_up=12, - ch_down=13, - ch_left=15, - ch_right=14, - elog=None, - name=None, - ): - self.Id = Id - self.name = name - self.diode_x = MotorRecord(Id + ":MOTOR_X1", name="diode_x") - self.diode_y = MotorRecord(Id + ":MOTOR_Y1", name="diode_y") - self.target_pos = MotorRecord(Id + ":MOTOR_PROBE", name="target_pos") - self.target = AdjustablePvEnum(Id + ":PROBE_SP", name="target") - if VME_crate: - self.diode_up = FeDigitizer("%s:Lnk%dCh%d" % (VME_crate, link, ch_up)) - self.diode_down = FeDigitizer("%s:Lnk%dCh%d" % (VME_crate, link, ch_down)) - self.diode_left = FeDigitizer("%s:Lnk%dCh%d" % (VME_crate, link, ch_left)) - self.diode_right = FeDigitizer("%s:Lnk%dCh%d" % (VME_crate, link, ch_right)) - - if self.name: - self.alias = Alias(name) - self.alias.append(self.diode_x.alias) - self.alias.append(self.diode_y.alias) - self.alias.append(self.target_pos.alias) - self.alias.append(self.target.alias) - - def __repr__(self): - s = f"**Intensity monitor {self.name}**\n\n" - - s += f"Target in: {self.target.get_current_value().name}\n\n" - try: - sd = "**Biasd voltage**\n" - sd += " - Diode up: %.4f\n" % (sdelf.diode_up.get_biasd()) - sd += " - Diode down: %.4f\n" % (sdelf.diode_down.get_biasd()) - sd += " - Diode left: %.4f\n" % (sdelf.diode_left.get_biasd()) - sd += " - Diode right: %.4f\n" % (sdelf.diode_right.get_biasd()) - sd += "\n" - - sd += "**Gain**\n" - sd += " - Diode up: %i\n" % (sdelf.diode_up.gain.get()) - sd += " - Diode down: %i\n" % (sdelf.diode_down.gain.get()) - sd += " - Diode left: %i\n" % (sdelf.diode_left.gain.get()) - sd += " - Diode right: %i\n" % (sdelf.diode_right.gain.get()) - s += sd - except: - pass - return s - - def set_gains(self, value): - try: - self.diode_up.gain.set(value) - self.diode_down.gain.set(value) - self.diode_left.gain.set(value) - self.diode_right.gain.set(value) - except: - print("No diodes configured, can not change any gain!") - - def get_available_gains(self): - try: - nu = self.diode_up.gain.names - nd = self.diode_down.gain.names - nl = self.diode_left.gain.names - nr = self.diode_right.gain.names - assert ( - nu == nd == nl == nr - ), "NB: the gain options of the four diodes are not equal!!!" - return nu - except: - print("No diodes configured, can not change any gain!") - - def get_gains(self): - try: - gains = dict() - gains["up"] = (self.diode_up.gain.get_name(), self.diode_up.gain.get()) - gains["down"] = ( - self.diode_down.gain.get_name(), - self.diode_down.gain.get(), - ) - gains["left"] = ( - self.diode_left.gain.get_name(), - self.diode_left.gain.get(), - ) - gains["right"] = ( - self.diode_right.gain.get_name(), - self.diode_right.gain.get(), - ) - return gains - except: - print("No diodes configured, can not change any gain!") - - # SAROP21-CVME-PBPS:Lnk10Ch15-WD-gain - - -from ..elements.assembly import Assembly - - class SolidTargetDetectorPBPS_new_assembly(Assembly): def __init__( self, diff --git a/eco/xoptics/att_usd.py b/eco/xoptics/att_usd.py index a66fcfe..a7189e9 100644 --- a/eco/xoptics/att_usd.py +++ b/eco/xoptics/att_usd.py @@ -289,8 +289,7 @@ class Att_usd(Assembly): def _updateE(self, energy=None, check_once=False): while not energy: - energy = PV("SARUN03-UIND030:FELPHOTENE").value - energy = energy * 1000 + energy = PV("SAROP21-ARAMIS:ENERGY").value if energy < self.E_min: energy = None print( @@ -298,7 +297,7 @@ class Att_usd(Assembly): ) sleep(self._sleeptime) self.E = energy - print("Set energy to %s eV" % energy) + print("Calculating transmission for %s eV" % energy) return def _calc_transmission(self): diff --git a/eco/xoptics/attenuator_aramis.py b/eco/xoptics/attenuator_aramis.py index ba7b17d..6e0b9f8 100755 --- a/eco/xoptics/attenuator_aramis.py +++ b/eco/xoptics/attenuator_aramis.py @@ -45,8 +45,7 @@ class AttenuatorAramis: def updateE(self, energy=None): while not energy: - energy = PV("SARUN03-UIND030:FELPHOTENE").value - energy = energy * 1000 + energy = PV("SAROP21-ARAMIS:ENERGY").value if energy < self.E_min: energy = None print( @@ -54,7 +53,7 @@ class AttenuatorAramis: ) sleep(self._sleeptime) PV(self.Id + ":ENERGY").put(energy) - print("Set energy to %s eV" % energy) + print("Calculating transmission for %s eV" % energy) return def set_transmission(self, value, energy=None): diff --git a/eco/xoptics/kb_bernina.py b/eco/xoptics/kb_bernina.py index 9a7f2ff..53ab721 100644 --- a/eco/xoptics/kb_bernina.py +++ b/eco/xoptics/kb_bernina.py @@ -10,7 +10,7 @@ from numbers import Number from tabulate import tabulate -class KBMirrorBernina_new(Assembly): +class KBMirrorBernina(Assembly): def __init__( self, pvname_ver, @@ -263,111 +263,6 @@ class KBMirrorBernina_new(Assembly): return focpos_hor, focpos_ver, out -class KBMirrorBernina: - def __init__( - self, - kb_ver=None, - kb_hor=None, - usd_table=None, - d_kbver=3350.0, - d_kbhor=2600.0, - d_hex=1600.0, - d_win1=1945.0, - d_win2=1330.0, - d_target=1520.0, - d_att=1420.0, - ): - """All distances are from sample interaction point at straight beam (no kb deflection), the units are expected in mm""" - self.kb_ver = kb_ver - self.kb_hor = kb_hor - self.usd_table = usd_table - self.d_kbver = d_kbver - self.d_kbhor = d_kbhor - self.d_hex = d_hex - self.d_att = d_att - self.d_win2 = d_win2 - self.d_win1 = d_win1 - self.d_target = d_target - - def calc_positions(self, the_kbver, the_kbhor): - """angles in rad""" - y_kbhor = np.tan(2 * the_kbver) * np.abs(self.d_kbver - self.d_kbhor) - rx_kbhor = -2 * the_kbver - y_hex = np.tan(2 * the_kbver) * np.abs(self.d_kbver - self.d_hex) - x_hex = np.tan(2 * the_kbhor) * np.abs(self.d_kbhor - self.d_hex) - rx_hex = rx_kbhor - ry_hex = 2 * the_kbhor - return { - "y_kbhor": y_kbhor, - "rx_kbhor": rx_kbhor, - "x_hex": x_hex, - "y_hex": y_hex, - "rx_hex": rx_hex, - "ry_hex": ry_hex, - } - - def calc_fwhm(self, fwhm_hor, fwhm_ver, z_focver=0, z_fochor=0, E_phot=None): - """E_phot in eV, length units in mm.""" - lam = constants.c * constants.h / constants.electron_volt / E_phot - print(lam * 1e10) - fwhm_fac = 1 / np.sqrt(2 * np.log(2)) # w = fwhm_fac*fwhm - # div_ver = np.arctan(fwhm_ver*fwhm_fac/2/(self.d_kbver+z_focver)) #half divergence - # div_hor = np.arctan(fwhm_hor*fwhm_fac/2/(self.d_kbhor+z_fochor)) - c = lam / np.pi * 1e3 - - w0 = lambda w, z: ( - w**2 - (w**4 - (2 * c * z) ** 2) ** 0.5 - ) ** 0.5 / np.sqrt(2) - w = lambda w0, z: (w0**2 + (c * z / w0) ** 2) ** 0.5 - zr = lambda w0: w0**2 / c - - fwhm_z = lambda z, w0: w(w0, z) / fwhm_fac - w0_hor = w0(fwhm_hor * fwhm_fac, self.d_kbhor + z_fochor) - w0_ver = w0(fwhm_ver * fwhm_fac, self.d_kbver + z_focver) - print(w0_hor) - res = {} - res["target"] = ( - fwhm_z(self.d_target + z_fochor, w0_hor), - fwhm_z(self.d_target + z_focver, w0_ver), - ) - res["win1"] = ( - fwhm_z(self.d_win1 + z_fochor, w0_hor), - fwhm_z(self.d_win1 + z_focver, w0_ver), - ) - res["win2"] = ( - fwhm_z(self.d_win2 + z_fochor, w0_hor), - fwhm_z(self.d_win2 + z_focver, w0_ver), - ) - res["att"] = ( - fwhm_z(self.d_att + z_fochor, w0_hor), - fwhm_z(self.d_att + z_focver, w0_ver), - ) - res["sample"] = (fwhm_z(z_fochor, w0_hor), fwhm_z(z_focver, w0_ver)) - # res['fwhm_kbver'] = (fwhm_z(self.d_kbver+z_fochor,w0_hor),fwhm_z(self.d_kbver+z_focver,w0_ver)) - # res['fwhm_kbhor'] = (fwhm_z(self.d_kbhor+z_fochor,w0_hor),fwhm_z(self.d_kbhor+z_focver,w0_ver)) - return res - - def move_hex_for_kb_angles(self, the_kbver, the_kbhor): - pos = self.calc_positions(the_kbver, the_kbhor) - x = pos["x_hex"] - y = pos["y_hex"] - rx = pos["rx_hex"] * 180 / np.pi - ry = pos["ry_hex"] * 180 / np.pi - z = rz = 0.0 - ax, ay, az, arx, ary, arz = self.usd_table.get_coordinates() - print( - f"present upstream large hexapod position is (x/mm,y/mm,z/mm,rx/°,ry/°,rz/°) = ({ax:g},{ay:g},{az:g},{arx:g},{ary:g},{arz:g})" - ) - print( - f"moving to (x/mm,y/mm,z/mm,rx/°,ry/°,rz/°) = ({x:g},{y:g},{z:g},{rx:g},{ry:g},{rz:g})" - ) - if not input("start moving upstream large hexapod? (y/n)") == "y": - print("did nothing") - return - else: - self.usd_table.move_to_coordinates(x, y, z, rx, ry, rz) - - def calc_focus_pos_intercept(size0, size1, distance): """calculates the position of the focus based on simple intercept theorem. position is from where size 0 was measured, and the focus will be between the diff --git a/eco/xoptics/reflaser.py b/eco/xoptics/reflaser.py old mode 100755 new mode 100644 index 6508cfd..23d4835 --- a/eco/xoptics/reflaser.py +++ b/eco/xoptics/reflaser.py @@ -1,26 +1,40 @@ from ..devices_general.motors import MotorRecord from epics import PV from ..aliases import Alias, append_object_to_object +from ..elements.assembly import Assembly -class RefLaser_Aramis: - def __init__(self, Id, elog=None, name=None, inpos=-18.947, outpos=-5): +class RefLaser_Aramis(Assembly): + def __init__(self, Id, elog=None, name=None, inpos=-18.818, outpos=-5): + super().__init__(name=name) self.Id = Id self.elog = elog - self.name = name + # append_object_to_object(self, + self._inpos = inpos self._outpos = outpos - self.mirrmotor = MotorRecord(self.Id + ":MOTOR_1") - self.x_trans = MotorRecord(self.Id + ":MOTOR_X1") - self.z_trans = MotorRecord(self.Id + ":MOTOR_Z1") - self.x_rot = MotorRecord(self.Id + ":MOTOR_ROT_X1") - self.z_rot = MotorRecord(self.Id + ":MOTOR_ROT_Z1") + self._append(MotorRecord, self.Id + ":MOTOR_1", name="mirror", is_setting=True) + self._append(MotorRecord, self.Id + ":MOTOR_X1", name="x1", is_setting=True) + self._append(MotorRecord, self.Id + ":MOTOR_Z1", name="z1", is_setting=True) + self._append( + MotorRecord, self.Id + ":MOTOR_ROT_X1", name="rx1", is_setting=True + ) + self._append( + MotorRecord, self.Id + ":MOTOR_ROT_Z1", name="rz1", is_setting=True + ) + pv_lir0 = "SAROP21-OLIR136" # TODO hardcoded + self._append(MotorRecord, pv_lir0 + ":MOTOR_MX", name="x_ap1", is_setting=True) + self._append(MotorRecord, pv_lir0 + ":MOTOR_MY", name="y_ap1", is_setting=True) + pv_lir1 = "SAROP21-OLIR138" # TODO hardcoded + self._append(MotorRecord, pv_lir1 + ":MOTOR_MX", name="x_ap2", is_setting=True) + self._append(MotorRecord, pv_lir1 + ":MOTOR_MY", name="y_ap2", is_setting=True) + self.mirror.set_limits(-20, 0) def __call__(self, *args, **kwargs): self.set(*args, **kwargs) def __str__(self): - status = self.get_status() + status = self.get_in_status() if status: return "Reflaser is In." elif status == False: @@ -28,8 +42,8 @@ class RefLaser_Aramis: elif status == None: return "Reflaser status not defined." - def get_status(self): - v = self.mirrmotor.get_current_value() + def get_in_status(self): + v = self.mirror.get_current_value() if abs(v - self._inpos) < 0.2: isin = True elif abs(v - self._outpos) < 0.2: @@ -47,9 +61,9 @@ class RefLaser_Aramis: else: print("String %s not recognized!" % value) if value: - self.mirrmotor.set_target_value(self._inpos) + self.mirror.set_target_value(self._inpos) else: - self.mirrmotor.set_target_value(self._outpos) + self.mirror.set_target_value(self._outpos) def movein(self): self.set("in") @@ -58,4 +72,4 @@ class RefLaser_Aramis: self.set("out") def __repr__(self): - return self.__str__() + return self.__str__() + "\n" + super().__repr__() diff --git a/eco/xoptics/reflaser_new.py b/eco/xoptics/reflaser_new.py deleted file mode 100644 index 23d4835..0000000 --- a/eco/xoptics/reflaser_new.py +++ /dev/null @@ -1,75 +0,0 @@ -from ..devices_general.motors import MotorRecord -from epics import PV -from ..aliases import Alias, append_object_to_object -from ..elements.assembly import Assembly - - -class RefLaser_Aramis(Assembly): - def __init__(self, Id, elog=None, name=None, inpos=-18.818, outpos=-5): - super().__init__(name=name) - self.Id = Id - self.elog = elog - # append_object_to_object(self, - - self._inpos = inpos - self._outpos = outpos - self._append(MotorRecord, self.Id + ":MOTOR_1", name="mirror", is_setting=True) - self._append(MotorRecord, self.Id + ":MOTOR_X1", name="x1", is_setting=True) - self._append(MotorRecord, self.Id + ":MOTOR_Z1", name="z1", is_setting=True) - self._append( - MotorRecord, self.Id + ":MOTOR_ROT_X1", name="rx1", is_setting=True - ) - self._append( - MotorRecord, self.Id + ":MOTOR_ROT_Z1", name="rz1", is_setting=True - ) - pv_lir0 = "SAROP21-OLIR136" # TODO hardcoded - self._append(MotorRecord, pv_lir0 + ":MOTOR_MX", name="x_ap1", is_setting=True) - self._append(MotorRecord, pv_lir0 + ":MOTOR_MY", name="y_ap1", is_setting=True) - pv_lir1 = "SAROP21-OLIR138" # TODO hardcoded - self._append(MotorRecord, pv_lir1 + ":MOTOR_MX", name="x_ap2", is_setting=True) - self._append(MotorRecord, pv_lir1 + ":MOTOR_MY", name="y_ap2", is_setting=True) - self.mirror.set_limits(-20, 0) - - def __call__(self, *args, **kwargs): - self.set(*args, **kwargs) - - def __str__(self): - status = self.get_in_status() - if status: - return "Reflaser is In." - elif status == False: - return "Reflaser is Out." - elif status == None: - return "Reflaser status not defined." - - def get_in_status(self): - v = self.mirror.get_current_value() - if abs(v - self._inpos) < 0.2: - isin = True - elif abs(v - self._outpos) < 0.2: - isin = False - else: - isin = None - return isin - - def set(self, value): - if type(value) is str: - if value.lower() == "in": - value = True - elif value.lower() == "out": - value = False - else: - print("String %s not recognized!" % value) - if value: - self.mirror.set_target_value(self._inpos) - else: - self.mirror.set_target_value(self._outpos) - - def movein(self): - self.set("in") - - def moveout(self): - self.set("out") - - def __repr__(self): - return self.__str__() + "\n" + super().__repr__() From cdac3b734ed6518bcbab7d6b26586c9e45736f42 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Fri, 19 Aug 2022 20:34:27 +0200 Subject: [PATCH 09/52] added pedestal copying to directory --- eco/bernina/bernina.py | 35 +++++++++++++++- eco/detector/jungfrau.py | 47 +++++++++++++++++++++- eco/endstations/bernina_diffractometers.py | 24 +++++++++-- 3 files changed, 100 insertions(+), 6 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 4e08205..96491a5 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -263,7 +263,6 @@ namespace.append_obj( lazy=True, ) - namespace.append_obj( "Pprm_dsd", pvname="SARES20-DSDPPRM", @@ -480,6 +479,7 @@ namespace.append_obj( Id="SARES21-XRD", configuration=config_bernina.xrd_config(), diff_detector={"jf_id": "JF01T03V01"}, + pgroup_adj=config_bernina.pgroup, invert_kappa_ellbow=config_bernina.invert_kappa_ellbow._value, name="xrd", lazy=True, @@ -726,6 +726,38 @@ def _copy_scan_info_to_raw(scan, daq=daq): print(f"Status: {response.json()['status']} Message: {response.json()['message']}") +from eco.detector import Jungfrau + + +def _copy_selected_JF_pedestals_to_raw(scan, daq=daq): + runno = daq.get_last_run_number() + pgroup = daq.pgroup + for jf_id in daq.channels["channels_JF"](): + jf = Jungfrau(jf_id, name="noname", pgroup_adj=config_bernina.pgroup) + print( + f"Copying {jf_id} pedestal to run {runno} in the raw directory of {pgroup}." + ) + response = daq.append_aux( + jf.get_present_pedestal_filename_in_run(intempdir=True), + pgroup=pgroup, + run_number=runno, + ) + print( + f"Status: {response.json()['status']} Message: {response.json()['message']}" + ) + print( + f"Copying {jf_id} gainmap to run {runno} in the raw directory of {pgroup}." + ) + response = daq.append_aux( + jf.get_present_gain_filename_in_run(intempdir=True), + pgroup=pgroup, + run_number=runno, + ) + print( + f"Status: {response.json()['status']} Message: {response.json()['message']}" + ) + + def _increment_daq_run_number(scan, daq=daq): try: daq_last_run_number = daq.get_last_run_number() @@ -755,6 +787,7 @@ callbacks_start_scan.append(_increment_daq_run_number) callbacks_end_scan = [_message_end_scan] callbacks_end_scan.append(_write_namespace_status_to_scan) callbacks_end_scan.append(_copy_scan_info_to_raw) +callbacks_end_scan.append(_copy_selected_JF_pedestals_to_raw) # >>>> Extract for run_table and elog diff --git a/eco/detector/jungfrau.py b/eco/detector/jungfrau.py index 37782ee..59a565d 100644 --- a/eco/detector/jungfrau.py +++ b/eco/detector/jungfrau.py @@ -1,3 +1,4 @@ +import shutil from tkinter import W from ..elements.adjustable import AdjustableVirtual, AdjustableGetSet from ..epics.adjustable import AdjustablePv @@ -16,11 +17,12 @@ class Jungfrau(Assembly): trigger_on=254, trigger_off=255, broker_address="http://sf-daq:10002", + pgroup_adj=None, name=None, ): super().__init__(name=name) self.alias = Alias(name, channel=jf_id, channeltype="JF") - + self.pgroup = pgroup_adj self.jf_id = jf_id self.broker_address = broker_address self._append( @@ -59,6 +61,24 @@ class Jungfrau(Assembly): name="gain_file", is_display=True, ) + self._append( + AdjustableGetSet, + self.get_present_pedestal_filename_in_run, + lambda value: NotImplementedError( + "Can not set the pedestal file manually yet." + ), + name="pedestal_file_in_run", + is_display=True, + ) + self._append( + AdjustableGetSet, + self.get_present_gain_filename_in_run, + lambda value: NotImplementedError( + "Can not set the pedestal file manually yet." + ), + name="gain_file_in_run", + is_display=True, + ) def _set_trigger_enable(self, value): if value: @@ -74,12 +94,37 @@ class Jungfrau(Assembly): else: raise Exception(f"File {filepath.as_posix()} seems not to exist!") + def get_present_gain_filename_in_run(self, intempdir=False): + f = Path(self.get_present_gain_filename()) + dest = Path( + f"/sf/bernina/data/{self.pgroup()}/res/tmp/gainmaps_{self.jf_id}.h5" + ) + if not dest.exists(): + shutil.copyfile(f, dest) + if intempdir: + return dest.as_posix() + else: + return f"aux/{dest.name}" + def get_present_pedestal_filename(self): searchpath = Path(f"/sf/jungfrau/data/pedestal/{self.jf_id}") filelist = list(searchpath.glob("*.h5")) times = [datetime.strptime(f.stem, "%Y%m%d_%H%M%S") for f in filelist] return filelist[times.index(max(times))].as_posix() + def get_present_pedestal_filename_in_run(self, intempdir=False): + f = Path(self.get_present_pedestal_filename()) + dest = Path( + f"/sf/bernina/data/{self.pgroup()}/res/tmp/pedestal_{self.jf_id}_{f.stem}.h5" + ) + if not dest.exists(): + shutil.copyfile(f, dest) + + if intempdir: + return dest.as_posix() + else: + return f"aux/{dest.name}" + def get_detector_frequency(self): return self._event_master.event_codes[ self._detectors_event_code diff --git a/eco/endstations/bernina_diffractometers.py b/eco/endstations/bernina_diffractometers.py index 2682432..7388740 100644 --- a/eco/endstations/bernina_diffractometers.py +++ b/eco/endstations/bernina_diffractometers.py @@ -16,6 +16,7 @@ from .kappa_conversion import kappa2you, you2kappa import numpy as np from ..utilities.recspace import Crystals + def addMotorRecordToSelf(self, name=None, Id=None): try: self.__dict__[name] = MotorRecord(Id, name=name) @@ -274,8 +275,7 @@ class GPS(Assembly): unit="deg", ) - #self._append(Crystals, diffractometer_you=self, name="crystals", is_display="recursive") - + # self._append(Crystals, diffractometer_you=self, name="crystals", is_display="recursive") def gui(self, guiType="xdm"): """Adjustable convention""" @@ -405,6 +405,7 @@ class XRDYou(Assembly): configuration=["base"], diff_detector=None, invert_kappa_ellbow=True, + pgroup_adj=None, ): """X-ray diffractometer platform in AiwssFEL Bernina.\ : list of elements mounted on @@ -767,9 +768,16 @@ class XRDYou(Assembly): name="det_diff", is_setting=False, is_display=False, + pgroup_adj=pgroup_adj, view_toplevel_only=True, ) - self._append(Crystals, diffractometer_you=self, name="crystals", is_setting=False, is_display=False) + self._append( + Crystals, + diffractometer_you=self, + name="crystals", + is_setting=False, + is_display=False, + ) def get_adjustable_positions_str(self): ostr = "*****XRD motor positions******\n" @@ -931,7 +939,14 @@ class XRDYou(Assembly): class XRD(Assembly): - def __init__(self, name=None, Id=None, configuration=["base"], diff_detector=None): + def __init__( + self, + name=None, + Id=None, + configuration=["base"], + diff_detector=None, + pgroup_adj=None, + ): """X-ray diffractometer platform in AiwssFEL Bernina.\ : list of elements mounted on the plaform, options are kappa, nutable, hlgonio, polana""" @@ -1156,6 +1171,7 @@ class XRD(Assembly): name="det_diff", is_setting=False, is_display=True, + pgroup_adj=pgroup_adj, view_toplevel_only=True, ) From 2fc5fb69471861124ea2ee5e80c85304ca7b16d4 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Mon, 29 Aug 2022 14:53:49 +0200 Subject: [PATCH 10/52] uncomment slit_mono --- eco/bernina/bernina.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 96491a5..23983f2 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -120,12 +120,12 @@ namespace.append_obj( name="slit_switch", module_name="eco.xoptics.slits", ) -# namespace.append_obj( -# "SlitBlades", -# "SAROP21-OAPU102", -# name="slit_mono", -# module_name="eco.xoptics.slits", -# ) +namespace.append_obj( + "SlitBlades", + "SAROP21-OAPU102", + name="slit_mono", + module_name="eco.xoptics.slits", +) from eco.devices_general.motors import SmaractStreamdevice, SmaractRecord From 255e204df4ddbfb326dadda05388b7ba40c16db9 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Thu, 1 Sep 2022 22:25:35 +0200 Subject: [PATCH 11/52] upgrades of wago, reflaser, bernina config, xeye, and some more. --- eco/bernina/bernina.py | 46 +++++++ eco/bernina/config.py | 44 +++---- eco/devices_general/motors.py | 53 ++++---- eco/devices_general/wago.py | 52 ++++++++ eco/elements/adj_obj.py | 6 + eco/elements/memory.py | 3 + eco/xdiagnostics/dsd.py | 8 +- eco/xdiagnostics/intensity_monitors.py | 163 ++++++++++++++++++++++++- eco/xoptics/kb_mirrors.py | 44 +++++-- eco/xoptics/reflaser.py | 77 ++++++++++-- 10 files changed, 428 insertions(+), 68 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 23983f2..eaacb8b 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -126,6 +126,12 @@ namespace.append_obj( name="slit_mono", module_name="eco.xoptics.slits", ) +namespace.append_obj( + "SolidTargetDetectorPBPS", + "SAROP21-PBPS103", + name="mon_mono", + module_name="eco.xdiagnostics.intensity_monitors", +) from eco.devices_general.motors import SmaractStreamdevice, SmaractRecord @@ -242,6 +248,13 @@ namespace.append_obj( module_name="eco.xdiagnostics.intensity_monitors", lazy=True, ) +namespace.append_obj( + "SolidTargetDetectorPBPS", + "SARFE10-PBPS053", + name="mon_und", + module_name="eco.xdiagnostics.intensity_monitors", +) + namespace.append_obj( "RefLaser_Aramis", "SAROP21-OLAS136", @@ -263,6 +276,10 @@ namespace.append_obj( lazy=True, ) +namespace.append_obj( + "DownstreamDiagnostic", name="dsd", module_name="eco.xdiagnostics.dsd" +) + namespace.append_obj( "Pprm_dsd", pvname="SARES20-DSDPPRM", @@ -443,6 +460,13 @@ namespace.append_obj( name="analog_inputs", module_name="eco.devices_general.wago", ) +namespace.append_obj( + "WagoAnalogOutputs", + "SARES20-CWAG-GPS01", + lazy=True, + name="analog_outputs", + module_name="eco.devices_general.wago", +) namespace.append_obj( "GudeStrip", "SARES20-CPPS-01", @@ -1345,6 +1369,17 @@ namespace.append_obj(JohannAnalyzer, name="analyzer") ############## experiment specific ############# + +namespace.append_obj( + "Bernina_XEYE", + zoomstage_pv=config_bernina.xeye.zoomstage_pv._value, + camera_pv=config_bernina.xeye.camera_pv._value, + bshost=config_bernina.xeye.bshost._value, + bsport=config_bernina.xeye.bsport._value, + name="xeye", + module_name="eco.xdiagnostics.profile_monitors", +) + # try to append pgroup folder to path !!!!! This caused eco to run in a timeout without error traceback !!!!! try: @@ -1365,6 +1400,17 @@ except: print("Did not succed to append an eco folder in current prgoup") +class Xspect_EH55(Assembly): + def __init__(self, name="xspect_bernina"): + super().__init__(name=name) + self._append(MotorRecord, "SARES20-MF1:MOT_15", name="x_crystal") + self._append(MotorRecord, "SARES20-MF1:MOT_16", name="y_crystal") + # self._append(SmaractRecord,'SARES20-MF1:MOT_16',name='theta_crystal') + + +namespace.append_obj(Xspect_EH55, name="xspect_bernina", lazy=True) + + #### pgroup specific appending, might be temporary at this location #### # namespace.append_obj("Xom", module_name="xom", name="xom", lazy=True) diff --git a/eco/bernina/config.py b/eco/bernina/config.py index 59cd577..7c16502 100755 --- a/eco/bernina/config.py +++ b/eco/bernina/config.py @@ -75,28 +75,28 @@ components = [ # "type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS", # "kwargs": {"VME_crate": "SAROP21-CVME-PBPS2", "link": 9}, # }, - { - "name": "mon_und", - "z_und": 53, - "desc": "Intensity/position monitor after Undulator", - "type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS_new", - "args": ["SARFE10-PBPS053"], - "kwargs": { - "VME_crate": "SAROP21-CVME-PBPS1", - "link": 9, - "channels": { - "up": "SLAAR21-LSCP1-FNS:CH6:VAL_GET", - "down": "SLAAR21-LSCP1-FNS:CH7:VAL_GET", - "left": "SLAAR21-LSCP1-FNS:CH4:VAL_GET", - "right": "SLAAR21-LSCP1-FNS:CH5:VAL_GET", - }, - "calc": { - "itot": "SLAAR21-LTIM01-EVR0:CALCI", - "xpos": "SLAAR21-LTIM01-EVR0:CALCX", - "ypos": "SLAAR21-LTIM01-EVR0:CALCY", - }, - }, - }, + # { + # "name": "mon_und", + # "z_und": 53, + # "desc": "Intensity/position monitor after Undulator", + # "type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS_new", + # "args": ["SARFE10-PBPS053"], + # "kwargs": { + # "VME_crate": "SAROP21-CVME-PBPS1", + # "link": 9, + # "channels": { + # "up": "SLAAR21-LSCP1-FNS:CH6:VAL_GET", + # "down": "SLAAR21-LSCP1-FNS:CH7:VAL_GET", + # "left": "SLAAR21-LSCP1-FNS:CH4:VAL_GET", + # "right": "SLAAR21-LSCP1-FNS:CH5:VAL_GET", + # }, + # "calc": { + # "itot": "SLAAR21-LTIM01-EVR0:CALCI", + # "xpos": "SLAAR21-LTIM01-EVR0:CALCX", + # "ypos": "SLAAR21-LTIM01-EVR0:CALCY", + # }, + # }, + # }, { "name": "pshut_und", "type": "eco.xoptics.shutters:PhotonShutter", diff --git a/eco/devices_general/motors.py b/eco/devices_general/motors.py index b1912b5..869529b 100755 --- a/eco/devices_general/motors.py +++ b/eco/devices_general/motors.py @@ -883,6 +883,35 @@ class SmaractRecord(Assembly): Alias(an, channel=".".join([pvname, af]), channeltype="CA") ) self._currentChange = None + + self._append( + AdjustablePvEnum, + self.pvname + "_POS_TYPE_RB", + pvname_set=self.pvname + "_POS_TYPE_SP", + name="sensor_type", + is_setting=True, + ) + self._append( + AdjustablePv, + self.pvname + "_MAX_FREQ", + name="max_frequency", + is_setting=True, + ) + self._append( + AdjustablePv, self.pvname + ".VELO", name="speed", is_setting=False + ) + self._append( + AdjustablePv, + self.pvname + ".ACCL", + name="acceleration_time", + is_setting=False, + ) + self._append( + AdjustablePv, self.pvname + ".LLM", name="limit_low", is_setting=False + ) + self._append( + AdjustablePv, self.pvname + ".HLM", name="limit_high", is_setting=False + ) self._append( AdjustablePvEnum, self.pvname + ".STAT", @@ -903,6 +932,7 @@ class SmaractRecord(Assembly): name="autoset_unit", is_setting=True, ) + self._append( AdjustablePv, self.pvname + ".HOMR", @@ -927,21 +957,7 @@ class SmaractRecord(Assembly): is_setting=False, is_display=True, ) - self._append( - AdjustablePv, self.pvname + ".VELO", name="speed", is_setting=False - ) - self._append( - AdjustablePv, - self.pvname + ".ACCL", - name="acceleration_time", - is_setting=False, - ) - self._append( - AdjustablePv, self.pvname + ".LLM", name="limit_low", is_setting=False - ) - self._append( - AdjustablePv, self.pvname + ".HLM", name="limit_high", is_setting=False - ) + self._append( AdjustablePvEnum, self.pvname + ".SPMG", name="mode", is_setting=False ) @@ -979,13 +995,6 @@ class SmaractRecord(Assembly): is_status=False, is_display=False, ) - self._append( - AdjustablePvEnum, - self.pvname + "_POS_TYPE_RB", - pvname_set=self.pvname + "_POS_TYPE_SP", - name="sensor_type", - is_setting=True, - ) if backlash_definition: self._append( AdjustablePv, diff --git a/eco/devices_general/wago.py b/eco/devices_general/wago.py index 87a0eda..d37a43b 100644 --- a/eco/devices_general/wago.py +++ b/eco/devices_general/wago.py @@ -42,3 +42,55 @@ class WagoAnalogInputs(Assembly): self.pvbase = pvbase for n in range(1, 9): self._append(AnalogInput, pvbase + f":ADC{n:02d}", name=f"ch{n:d}") + + +class AnalogOutput(Assembly): + def __init__(self, pvname, name=None): + super().__init__(name=name) + self.pvname = pvname + self._append( + AdjustablePv, + self.pvname, + self.pvname + "_RB", + name="value", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePvString, + self.pvname + ".DESC", + name="description", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePvString, + self.pvname + ".EGU", + name="unit", + is_setting=False, + is_display=False, + ) + self._append( + DetectorPvData, + self.pvname + ".RVAL", + name="raw", + is_setting=False, + is_display=False, + ) + + def get_current_value(self): + return self.value.get_current_value() + + def __call__(self, *args): + if args: + self.value(*args).wait() + else: + return self.value.get_current_value() + + +class WagoAnalogOutputs(Assembly): + def __init__(self, pvbase, name=None): + super().__init__(name=name) + self.pvbase = pvbase + for n in range(1, 9): + self._append(AnalogOutput, pvbase + f":DAC{n:02d}", name=f"ch{n:d}") diff --git a/eco/elements/adj_obj.py b/eco/elements/adj_obj.py index 5289e50..3d86ea5 100644 --- a/eco/elements/adj_obj.py +++ b/eco/elements/adj_obj.py @@ -23,6 +23,12 @@ class AdjustableObject(Assembly): raise Exception(f"{fieldname} is not in dictionary") return d[fieldname] + def update_base_dict(self, updatedict): + tmp = self._base_dict.get_current_value() + tmp.update(updatedict) + self._base_dict.set_target_value(tmp) + self.__init__(self._base_dict, name=self.name) + def init_object(self): # super().__init__(name=self.name) for k, v in self._base_dict.get_current_value().items(): diff --git a/eco/elements/memory.py b/eco/elements/memory.py index 50fb2b5..e5cb6fc 100644 --- a/eco/elements/memory.py +++ b/eco/elements/memory.py @@ -125,6 +125,7 @@ class Memory: show_changes_only=True, set_changes_only=True, check_limits=True, + change_serially=False, force=False, ): # if input_obj: @@ -160,6 +161,8 @@ class Memory: changes.append(to.set_target_value(val, check=check_limits)) else: changes.append(to.set_target_value(val)) + if change_serially: + changes[-1].wait() if wait: for change in changes: change.wait() diff --git a/eco/xdiagnostics/dsd.py b/eco/xdiagnostics/dsd.py index 8d25741..18ff37a 100644 --- a/eco/xdiagnostics/dsd.py +++ b/eco/xdiagnostics/dsd.py @@ -10,6 +10,7 @@ from ..elements.assembly import Assembly from .profile_monitors import Pprm_dsd from .intensity_monitors import SolidTargetDetectorPBPS_new_assembly import numpy as np +from epics import PV class DownstreamDiagnostic(Assembly): @@ -24,9 +25,14 @@ class DownstreamDiagnostic(Assembly): self._append( MotorRecord, "SARES20-DSD:MOTOR_DSDY", name="ybase", is_setting=True ) - def get_xyposition_for_kb_angles_in_rad(self, theta_kbver, theta_kbhor): y = np.tan(2 * theta_kbver) * 7075 x = np.tan(2 * theta_kbhor) / np.cos(2 * theta_kbver) * 6325 return x, y + + def home(self): + self._run_cmd("python /ioc/qt/ESB_DSD_home.py SARES20-DSD") + + def gui(self): + self._run_cmd("caqtdm -noMsg -macro P=SARES20-DSD /ioc/qt/ESB_DSD_motors.ui") diff --git a/eco/xdiagnostics/intensity_monitors.py b/eco/xdiagnostics/intensity_monitors.py index bd0eed0..de66e32 100755 --- a/eco/xdiagnostics/intensity_monitors.py +++ b/eco/xdiagnostics/intensity_monitors.py @@ -63,7 +63,7 @@ class SolidTargetDetectorPBPS(Assembly): # ch_left=15, # ch_right=14, # elog=None, - # name=None, + name=None, # calc=None, # calc_calib={}, ): @@ -95,6 +95,167 @@ class SolidTargetDetectorPBPS(Assembly): DetectorPvDataStream, pvname + ":YPOS", name="ypos", is_setting=False ) + # Calibration calculation record + + # Intensity + self._append( + AdjustablePv, + pvname + ":INTENSITY.INPA", + name="calc_intensity_input_A", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + pvname + ":INTENSITY.INPB", + name="calc_intensity_input_B", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + pvname + ":INTENSITY.INPC", + name="calc_intensity_input_C", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + pvname + ":INTENSITY.INPD", + name="calc_intensity_input_D", + is_setting=True, + is_display=False, + ) + + self._append( + AdjustablePv, + pvname + ":INTENSITY.E", + name="calc_intensity_const_E", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + pvname + ":INTENSITY.F", + name="calc_intensity_const_F", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + pvname + ":INTENSITY.G", + name="calc_intensity_const_G", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + pvname + ":INTENSITY.H", + name="calc_intensity_const_H", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + pvname + ":INTENSITY.CALC", + name="calc_intensity_function", + is_setting=True, + is_display=False, + ) + # X position + self._append( + AdjustablePv, + pvname + ":XPOS.INPA", + name="calc_xpos_input_A", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + pvname + ":XPOS.INPB", + name="calc_xpos_input_B", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + pvname + ":XPOS.CALC", + name="calc_xpos_function", + is_setting=True, + is_display=False, + ) + + # self._append( + # AdjustablePv, pvname + ":XPOS.INPD", name="calc_input_D", is_setting=True, is_display=False + # ) + + # self._append( + # AdjustablePv, pvname + ":XPOS.IE", name="calc_input_E", is_setting=True, is_display=False + + # self._append( + # AdjustablePv, pvname + ":XPOS.IF", name="calc_input_F", is_setting=True, is_display=False + # ) + # self._append( + # AdjustablePv, pvname + ":XPOS.INPG", name="calc_input_G", is_setting=True, is_display=False + # ) + # self._append( + # AdjustablePv, pvname + ":XPOS.INPH", name="calc_input_H", is_setting=True, is_display=False + # ) + # self._append( + # AdjustablePv, pvname + ":XPOS.CALC", name="calc_function", is_setting=True, is_display=False + # ) + + # # Intensity + # # Set channels + # # Input data + # ep.PV(Devive_prefix+'INTENSITY.INPA').put(bytes(channels[0], "utf8")) + # ep.PV(Devive_prefix+'INTENSITY.INPB').put(bytes(channels[1], "utf8")) + # ep.PV(Devive_prefix+'INTENSITY.INPC').put(bytes(channels[2], "utf8")) + # ep.PV(Devive_prefix+'INTENSITY.INPD').put(bytes(channels[3], "utf8")) + # # Calibration values + # ep.PV(Devive_prefix+'INTENSITY.E').put(bytes(str(norm_diodes[0,0]), "utf8")) + # ep.PV(Devive_prefix+'INTENSITY.F').put(bytes(str(norm_diodes[0,1]), "utf8")) + # ep.PV(Devive_prefix+'INTENSITY.G').put(bytes(str(norm_diodes[0,2]), "utf8")) + # ep.PV(Devive_prefix+'INTENSITY.H').put(bytes(str(norm_diodes[0,3]), "utf8")) + # # Calculation + # ep.PV(Devive_prefix+'INTENSITY.CALC').put(bytes("A*E+B*F+C*G+D*H", "utf8")) + + # # XPOS + # # Set channels + # ep.PV(Devive_prefix+'XPOS.INPA').put(bytes(channels[2], "utf8")) + # ep.PV(Devive_prefix+'XPOS.INPB').put(bytes(channels[3], "utf8")) + # # Threshold value + # ep.PV(Devive_prefix+'XPOS.D').put(bytes(str(0.2), "utf8")) + # # Diode calibration value + # ep.PV(Devive_prefix+'XPOS.E').put(bytes(str(norm_diodes[0,2]), "utf8")) + # ep.PV(Devive_prefix+'XPOS.F').put(bytes(str(norm_diodes[0,3]), "utf8")) + # # Null value + # ep.PV(Devive_prefix+'XPOS.G').put(bytes(str(0), "utf8")) + # # Position calibration value + # ep.PV(Devive_prefix+'XPOS.I').put(bytes(str((Scan_x_range[1]-Scan_x_range[0])/ np.diff(scan_x_norm).mean()), "utf8")) + # # Intensity threshold value + # ep.PV(Devive_prefix+'XPOS.INPJ').put(bytes(Devive_prefix+'INTENSITY', "utf8")) + # # Calculation + # ep.PV(Devive_prefix+'XPOS.CALC').put(bytes("J Date: Thu, 1 Sep 2022 22:26:52 +0200 Subject: [PATCH 12/52] as befire --- eco/bernina/config.py | 8 -------- eco/devices_general/wago.py | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/eco/bernina/config.py b/eco/bernina/config.py index 7c16502..742e55b 100755 --- a/eco/bernina/config.py +++ b/eco/bernina/config.py @@ -620,14 +620,6 @@ components = [ # }, # }, # }, - { - "args": [], - "name": "dsd", - "z_und": 146, - "desc": "downstream diagnostics", - "type": "eco.xdiagnostics.dsd:DownstreamDiagnostic", - "kwargs": {}, - }, ] try: diff --git a/eco/devices_general/wago.py b/eco/devices_general/wago.py index d37a43b..687dd4d 100644 --- a/eco/devices_general/wago.py +++ b/eco/devices_general/wago.py @@ -83,7 +83,7 @@ class AnalogOutput(Assembly): def __call__(self, *args): if args: - self.value(*args).wait() + self.value.set_target_Value(*args).wait() else: return self.value.get_current_value() From 2bb347c6e5088963dc716f616ae5a6974ac35bae Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Sun, 4 Sep 2022 18:29:35 +0200 Subject: [PATCH 13/52] fixes in many before commissioning --- eco/bernina/bernina.py | 86 ++++++++++++- eco/devices_general/motors.py | 23 ++-- eco/timing/event_timing_new_new.py | 13 +- eco/utilities/config.py | 5 +- eco/xdiagnostics/intensity_monitors.py | 162 +++++++++++++------------ eco/xdiagnostics/profile_monitors.py | 17 +-- eco/xdiagnostics/xspect.py | 75 ++++-------- eco/xoptics/slits.py | 29 ++--- 8 files changed, 242 insertions(+), 168 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index eaacb8b..85b7f66 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -276,6 +276,56 @@ namespace.append_obj( lazy=True, ) +namespace.append_obj( + "Pprm", + "SARFE10-PPRM064", + "SARFE10-PPRM064", + module_name="eco.xdiagnostics.profile_monitors", + name="prof_fe", +) + +namespace.append_obj( + "Pprm", + "SAROP11-PPRM066", + "SAROP11-PPRM066", + module_name="eco.xdiagnostics.profile_monitors", + name="prof_mirr_alv1", +) + +namespace.append_obj( + "Pprm", + "SAROP21-PPRM094", + "SAROP21-PPRM094", + module_name="eco.xdiagnostics.profile_monitors", + name="prof_mirr1", +) + +namespace.append_obj( + "Pprm", + "SAROP21-PPRM113", + "SAROP21-PPRM113", + module_name="eco.xdiagnostics.profile_monitors", + name="prof_mono", +) + + +namespace.append_obj( + "Pprm", + "SAROP21-PPRM133", + "SAROP21-PPRM133", + module_name="eco.xdiagnostics.profile_monitors", + name="prof_opt", +) + + +namespace.append_obj( + "Pprm", + "SAROP21-PPRM138", + "SAROP21-PPRM138", + module_name="eco.xdiagnostics.profile_monitors", + name="prof_att", +) + namespace.append_obj( "DownstreamDiagnostic", name="dsd", module_name="eco.xdiagnostics.dsd" ) @@ -334,7 +384,6 @@ namespace.append_obj( name="tt_kb", lazy=True, ) - namespace.append_obj( "EventReceiver", "SARES20-CVME-01-EVR0", @@ -381,6 +430,30 @@ namespace.append_obj( lazy=True, # lazy=False, ) +namespace.append_obj( + "EventReceiver", + "SGE-CPCW-73-EVR0", + event_master, + n_pulsers=16, + n_output_front=16, + n_output_rear=0, + name="evr_camserver73", + module_name="eco.timing.event_timing_new_new", + lazy=True, + # lazy=False, +) +namespace.append_obj( + "EventReceiver", + "SGE-CPCW-74-EVR0", + event_master, + n_pulsers=16, + n_output_front=16, + n_output_rear=0, + name="evr_camserver74", + module_name="eco.timing.event_timing_new_new", + lazy=True, + # lazy=False, +) namespace.append_obj( "EventReceiver", "SGE-CPCW-83-EVR0", @@ -453,6 +526,17 @@ namespace.append_obj( name="cam_south", module_name="eco.devices_general.cameras_ptz", ) +namespace.append_obj( + "Xspect", + name="xspect", + module_name="eco.xdiagnostics.xspect", +) +namespace.append_obj( + "SlitPosWidth", + "SAROP21-OAPU136", + name="slit_att", + module_name="eco.xoptics.slits", +), namespace.append_obj( "WagoAnalogInputs", "SARES20-CWAG-GPS01", diff --git a/eco/devices_general/motors.py b/eco/devices_general/motors.py index 869529b..ec7950e 100755 --- a/eco/devices_general/motors.py +++ b/eco/devices_general/motors.py @@ -897,20 +897,18 @@ class SmaractRecord(Assembly): name="max_frequency", is_setting=True, ) - self._append( - AdjustablePv, self.pvname + ".VELO", name="speed", is_setting=False - ) + self._append(AdjustablePv, self.pvname + ".VELO", name="speed", is_setting=True) self._append( AdjustablePv, self.pvname + ".ACCL", name="acceleration_time", - is_setting=False, + is_setting=True, ) self._append( - AdjustablePv, self.pvname + ".LLM", name="limit_low", is_setting=False + AdjustablePv, self.pvname + ".LLM", name="limit_low", is_setting=True ) self._append( - AdjustablePv, self.pvname + ".HLM", name="limit_high", is_setting=False + AdjustablePv, self.pvname + ".HLM", name="limit_high", is_setting=True ) self._append( AdjustablePvEnum, @@ -972,26 +970,21 @@ class SmaractRecord(Assembly): is_display="recursive", is_status=True, ) - # self._append( - # AdjustablePvEnum, - # self.pvname + ".SPMG", - # name="motor_state", - # is_setting=False, - # ) + self._append( - AdjustablePvString, self.pvname + ".EGU", name="unit", is_setting=False + AdjustablePvString, self.pvname + ".EGU", name="unit", is_setting=True ) self._append( AdjustablePvString, self.pvname + ".DESC", name="description", - is_setting=False, + is_setting=True, ) self._append( AdjustablePv, self.pvname + "_CAL_CMD", name="_calibrate_sensor", - is_setting=False, + is_setting=True, is_status=False, is_display=False, ) diff --git a/eco/timing/event_timing_new_new.py b/eco/timing/event_timing_new_new.py index b70d994..cb1fa71 100644 --- a/eco/timing/event_timing_new_new.py +++ b/eco/timing/event_timing_new_new.py @@ -212,7 +212,7 @@ class MasterEventSystem(Assembly): for s, c in zip(slots, codes): if not c == None: if c in codes_out: - print(f"Code {c} exists multiple times!") + # print(f"Code {c} exists multiple times!") continue slots_out.append(s) codes_out.append(c) @@ -551,6 +551,17 @@ class EventReceiver(Assembly): # to._pulsers = self.pulsers self.outputs = outputs + self._append( + AdjustablePv, + self.pvname + ":SYSRESET", + is_status=False, + is_setting=False, + name="restart_ioc_pv", + ) + + def restart_ioc(self): + self.restart_ioc_pv.set_target_value(1) + def gui(self): dev = self.pvname.split("-")[-1] sys = self.pvname[: -(len(dev) + 1)] diff --git a/eco/utilities/config.py b/eco/utilities/config.py index 2229d91..6b770b8 100644 --- a/eco/utilities/config.py +++ b/eco/utilities/config.py @@ -2,6 +2,7 @@ import json import importlib from pathlib import Path import sys +from time import time from colorama import Fore as _color from functools import partial @@ -313,6 +314,7 @@ class Namespace(Assembly): N_cycles=4, silent=True, ): + starttime = time() if silent: self.silently_initializing = True print( @@ -384,6 +386,7 @@ class Namespace(Assembly): f"Initialized {len(self.initialized_names)} of {len(self.all_names)}." ) print("Failed objects: " + ", ".join(self.lazy_names)) + print(f"Initialisation took {time()-starttime} seconds") # if verbose: # print(("Configuring %s " % (name)).ljust(25), end="") @@ -417,7 +420,7 @@ class Namespace(Assembly): aliases_out = [] for channeltype in channeltypes: for alias in aliases: - if alias['channeltype']==channeltype: + if alias["channeltype"] == channeltype: aliases_out.append(alias) if not channeltypes: aliases_out = aliases diff --git a/eco/xdiagnostics/intensity_monitors.py b/eco/xdiagnostics/intensity_monitors.py index de66e32..198330e 100755 --- a/eco/xdiagnostics/intensity_monitors.py +++ b/eco/xdiagnostics/intensity_monitors.py @@ -50,6 +50,83 @@ class FeDigitiza(Assembly): # ] +class CalibrationRecord(Assembly): + def __init__(self, pvbase, name=None): + self.pvbase = pvbase + super().__init__(name) + self._append( + AdjustablePv, + self.pvbase + ".INPA", + name="input_A", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePv, + self.pvbase + ".INPB", + name="input_B", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePv, + self.pvbase + ".INPC", + name="input_C", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePv, + self.pvbase + ".INPD", + name="input_D", + is_setting=True, + is_display=True, + ) + + self._append( + AdjustablePv, + self.pvbase + ".E", + name="const_E", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePv, + self.pvbase + ".F", + name="const_F", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePv, + self.pvbase + ".G", + name="const_G", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePv, + self.pvbase + ".H", + name="const_H", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePv, + self.pvbase + ".I", + name="const_I", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePv, + self.pvbase + ".CALC", + name="function", + is_setting=True, + is_display=True, + ) + + class SolidTargetDetectorPBPS(Assembly): def __init__( self, @@ -97,90 +174,25 @@ class SolidTargetDetectorPBPS(Assembly): # Calibration calculation record - # Intensity + # Calibration self._append( - AdjustablePv, - pvname + ":INTENSITY.INPA", - name="calc_intensity_input_A", + CalibrationRecord, + pvname + ":INTENSITY", + name="calib_intensity", is_setting=True, is_display=False, ) self._append( - AdjustablePv, - pvname + ":INTENSITY.INPB", - name="calc_intensity_input_B", + CalibrationRecord, + pvname + ":XPOS", + name="calib_xpos", is_setting=True, is_display=False, ) self._append( - AdjustablePv, - pvname + ":INTENSITY.INPC", - name="calc_intensity_input_C", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePv, - pvname + ":INTENSITY.INPD", - name="calc_intensity_input_D", - is_setting=True, - is_display=False, - ) - - self._append( - AdjustablePv, - pvname + ":INTENSITY.E", - name="calc_intensity_const_E", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePv, - pvname + ":INTENSITY.F", - name="calc_intensity_const_F", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePv, - pvname + ":INTENSITY.G", - name="calc_intensity_const_G", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePv, - pvname + ":INTENSITY.H", - name="calc_intensity_const_H", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePv, - pvname + ":INTENSITY.CALC", - name="calc_intensity_function", - is_setting=True, - is_display=False, - ) - # X position - self._append( - AdjustablePv, - pvname + ":XPOS.INPA", - name="calc_xpos_input_A", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePv, - pvname + ":XPOS.INPB", - name="calc_xpos_input_B", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePv, - pvname + ":XPOS.CALC", - name="calc_xpos_function", + CalibrationRecord, + pvname + ":YPOS", + name="calib_ypos", is_setting=True, is_display=False, ) diff --git a/eco/xdiagnostics/profile_monitors.py b/eco/xdiagnostics/profile_monitors.py index a5f944b..591b85e 100755 --- a/eco/xdiagnostics/profile_monitors.py +++ b/eco/xdiagnostics/profile_monitors.py @@ -18,6 +18,11 @@ class Pprm(Assembly): def __init__(self, pvname, pvname_camera, name=None): super().__init__(name=name) self.pvname = pvname + + self._append( + AdjustablePvEnum, self.pvname + ":PROBE_SP", name="target", is_setting=True + ) + self._append( MotorRecord, pvname_camera + ":MOTOR_PROBE", @@ -31,13 +36,11 @@ class Pprm(Assembly): camserver_alias=f"{name} ({pvname_camera})", name="camera", is_setting=True, + is_display="recursive", ) self._append( AdjustablePvEnum, self.pvname + ":LED", name="led", is_setting=True ) - self._append( - AdjustablePvEnum, self.pvname + ":PROBE_SP", name="target", is_setting=True - ) def movein(self, target=1): self.target.set_target_value(target) @@ -45,10 +48,10 @@ class Pprm(Assembly): def moveout(self, target=0): self.target.set_target_value(target) - def __repr__(self): - s = f"**Profile Monitor {self.name}**\n" - s += f"Target in beam: {self.target.get_current_value().name}\n" - return s + # def __repr__(self): + # s = f"**Profile Monitor {self.name}**\n" + # s += f"Target in beam: {self.target.get_current_value().name}\n" + # return s class Target_xyz(Assembly): diff --git a/eco/xdiagnostics/xspect.py b/eco/xdiagnostics/xspect.py index 77bc0ed..ff86603 100644 --- a/eco/xdiagnostics/xspect.py +++ b/eco/xdiagnostics/xspect.py @@ -1,59 +1,30 @@ +from eco.elements.assembly import Assembly from ..aliases import Alias, append_object_to_object from ..devices_general.motors import MotorRecord from ..epics.adjustable import AdjustablePv, AdjustablePvEnum -class Xspect: +class Xspect(Assembly): def __init__(self, name=None): - self.alias = Alias(name) - append_object_to_object( - self, MotorRecord, "SARFE10-PSSS055:MOTOR_X1", name="x_grating" - ) - append_object_to_object( - self, MotorRecord, "SARFE10-PSSS055:MOTOR_Y1", name="y_grating" - ) - append_object_to_object( - self, MotorRecord, "SARFE10-PSSS055:MOTOR_ROT_X1", name="rx_grating" - ) - append_object_to_object( - self, MotorRecord, "SARFE10-PSSS055:MOTOR_PROBE", name="transl_probe" - ) - append_object_to_object( - self, MotorRecord, "SARFE10-PSSS059:MOTOR_X2", name="x_girder" - ) - append_object_to_object( - self, MotorRecord, "SARFE10-PSSS059:MOTOR_X3", name="x_crystal" - ) - append_object_to_object( - self, MotorRecord, "SARFE10-PSSS059:MOTOR_Y3", name="y_crystal" - ) - append_object_to_object( - self, MotorRecord, "SARFE10-PSSS059:MOTOR_ROT_X3", name="rx_crystal" - ) - append_object_to_object( - self, MotorRecord, "SARFE10-PSSS059:MOTOR_Y4", name="y_alignment" - ) - append_object_to_object( - self, MotorRecord, "SARFE10-PSSS059:MOTOR_ROT_X4", name="rx_camera" - ) - append_object_to_object( - self, MotorRecord, "SARFE10-PSSS059:MOTOR_X5", name="x_camera" - ) - append_object_to_object( - self, AdjustablePvEnum, "SARFE10-PSSS055:GRATING_SP", name="grid_type" - ) - append_object_to_object( - self, AdjustablePvEnum, "SARFE10-PSSS059:CRYSTAL_SP", name="crystal_type" - ) - append_object_to_object( - self, AdjustablePvEnum, "SARFE10-PSSS055:PROBE_SP", name="probe" - ) - append_object_to_object( - self, AdjustablePv, "SARFE10-PSSS059:ENERGY", name="energy_center_setpoint" - ) - append_object_to_object( - self, AdjustablePv, "SARFE10-PSSS059:MOTOR_Z5", name="camera_z" - ) - - + super().__init__(name=name) + self._append(MotorRecord, "SARFE10-PSSS055:MOTOR_X1", name="x_grating") + self._append(MotorRecord, "SARFE10-PSSS055:MOTOR_Y1", name="y_grating") + self._append(MotorRecord, "SARFE10-PSSS055:MOTOR_ROT_X1", name="rx_grating") + self._append(MotorRecord, "SARFE10-PSSS055:MOTOR_PROBE", name="transl_probe") + self._append(MotorRecord, "SARFE10-PSSS059:MOTOR_X2", name="x_girder") + self._append(MotorRecord, "SARFE10-PSSS059:MOTOR_X3", name="x_crystal") + self._append(MotorRecord, "SARFE10-PSSS059:MOTOR_Y3", name="y_crystal") + self._append(MotorRecord, "SARFE10-PSSS059:MOTOR_ROT_X3", name="rx_crystal") + self._append(MotorRecord, "SARFE10-PSSS059:MOTOR_Y4", name="y_alignment") + self._append(MotorRecord, "SARFE10-PSSS059:MOTOR_ROT_X4", name="rx_camera") + self._append(MotorRecord, "SARFE10-PSSS059:MOTOR_X5", name="x_camera") + self._append(AdjustablePvEnum, "SARFE10-PSSS055:GRATING_SP", name="grid_type") + self._append( + AdjustablePvEnum, "SARFE10-PSSS059:CRYSTAL_SP", name="crystal_type" + ) + self._append(AdjustablePvEnum, "SARFE10-PSSS055:PROBE_SP", name="probe") + self._append( + AdjustablePv, "SARFE10-PSSS059:ENERGY", name="energy_center_setpoint" + ) + self._append(AdjustablePv, "SARFE10-PSSS059:MOTOR_Z5", name="camera_z") diff --git a/eco/xoptics/slits.py b/eco/xoptics/slits.py index ee89dbb..85f8b4a 100755 --- a/eco/xoptics/slits.py +++ b/eco/xoptics/slits.py @@ -329,15 +329,16 @@ class SlitBlades(Assembly): @addSlitRepr -class SlitPosWidth: +class SlitPosWidth(Assembly): def __init__(self, pvname, name=None, elog=None): - self.name = name - self.Id = pvname - self.alias = Alias(name) - append_object_to_object(self, MotorRecord, pvname + ":MOTOR_X", name="hpos") - append_object_to_object(self, MotorRecord, pvname + ":MOTOR_Y", name="vpos") - append_object_to_object(self, MotorRecord, pvname + ":MOTOR_W", name="hgap") - append_object_to_object(self, MotorRecord, pvname + ":MOTOR_H", name="vgap") + super().__init__(name=name) + + self.pvname = pvname + + self._append(MotorRecord, pvname + ":MOTOR_X", name="hpos") + self._append(MotorRecord, pvname + ":MOTOR_Y", name="vpos") + self._append(MotorRecord, pvname + ":MOTOR_W", name="hgap") + self._append(MotorRecord, pvname + ":MOTOR_H", name="vgap") def getblade(pos, gap, direction=1): return pos + direction * gap / 2 @@ -367,8 +368,7 @@ class SlitPosWidth: [x + tx * self.vgap.get_current_value() for tx in [-1 / 2, 1 / 2]] ) - append_object_to_object( - self, + self._append( AdjustableVirtual, [self.vpos, self.vgap], partial(getblade, direction=1), @@ -376,8 +376,7 @@ class SlitPosWidth: reset_current_value_to=True, name="up", ) - append_object_to_object( - self, + self._append( AdjustableVirtual, [self.vpos, self.vgap], partial(getblade, direction=-1), @@ -385,8 +384,7 @@ class SlitPosWidth: reset_current_value_to=True, name="down", ) - append_object_to_object( - self, + self._append( AdjustableVirtual, [self.hpos, self.hgap], partial(getblade, direction=1), @@ -394,8 +392,7 @@ class SlitPosWidth: reset_current_value_to=True, name="left", ) - append_object_to_object( - self, + self._append( AdjustableVirtual, [self.hpos, self.hgap], partial(getblade, direction=-1), From 678a7de458df023ef8b296e6424b28b3051abf0b Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Wed, 7 Sep 2022 08:18:47 +0200 Subject: [PATCH 14/52] aramis_attenuator: added second PV check for photon energy if the main PV is NaN. slits: Changed _apply_on_all_blades method of SlitBladesGeneral class to check for methods if the methhod_name is not in the dict keys --- eco/bernina/bernina.py | 85 ++++++++-- eco/devices_general/motors.py | 45 +++++- eco/dummy/config.py | 14 +- eco/timing/event_timing_new_new.py | 4 +- eco/xdiagnostics/intensity_monitors.py | 208 ++++++++----------------- eco/xdiagnostics/profile_monitors.py | 7 +- eco/xoptics/attenuator_aramis.py | 4 +- eco/xoptics/offsetMirrors_new.py | 35 +++++ eco/xoptics/reflaser.py | 3 +- eco/xoptics/slits.py | 5 +- 10 files changed, 234 insertions(+), 176 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 85b7f66..49968e4 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -73,6 +73,7 @@ namespace.append_obj( "/photonics/home/gac-bernina/eco/configuration/run_table_channels_CA", name="_env_channels_ca", module_name="eco.elements.adjustable", + lazy=True, ) namespace.append_obj( "Run_Table2", @@ -119,18 +120,27 @@ namespace.append_obj( "SAROP21-OAPU092", name="slit_switch", module_name="eco.xoptics.slits", + lazy=True, ) namespace.append_obj( "SlitBlades", "SAROP21-OAPU102", name="slit_mono", module_name="eco.xoptics.slits", + lazy=True, ) namespace.append_obj( "SolidTargetDetectorPBPS", "SAROP21-PBPS103", + diode_channels_raw={ + "up": "SAROP21-CVME-PBPS1:Lnk9Ch3-DATA-SUM", + "down": "SAROP21-CVME-PBPS1:Lnk9Ch4-DATA-SUM", + "left": "SAROP21-CVME-PBPS1:Lnk9Ch2-DATA-SUM", + "right": "SAROP21-CVME-PBPS1:Lnk9Ch1-DATA-SUM", + }, name="mon_mono", module_name="eco.xdiagnostics.intensity_monitors", + lazy=True, ) from eco.devices_general.motors import SmaractStreamdevice, SmaractRecord @@ -251,8 +261,15 @@ namespace.append_obj( namespace.append_obj( "SolidTargetDetectorPBPS", "SARFE10-PBPS053", + diode_channels_raw={ + "up": "SARFE10-CVME-PHO6212:Lnk9Ch13-DATA-SUM", + "down": "SARFE10-CVME-PHO6212:Lnk9Ch12-DATA-SUM", + "left": "SARFE10-CVME-PHO6212:Lnk9Ch14-DATA-SUM", + "right": "SARFE10-CVME-PHO6212:Lnk9Ch15-DATA-SUM", + }, name="mon_und", module_name="eco.xdiagnostics.intensity_monitors", + lazy=True, ) namespace.append_obj( @@ -263,14 +280,14 @@ namespace.append_obj( lazy=True, ) namespace.append_obj( - "SolidTargetDetectorPBPS_assi", + "SolidTargetDetectorPBPS", "SAROP21-PBPS133", - pvname_fedigitizerchannels=dict( - up="SAROP21-CVME-PBPS1:Lnk9Ch0", - down="SAROP21-CVME-PBPS1:Lnk9Ch12", - left="SAROP21-CVME-PBPS1:Lnk9Ch15", - right="SAROP21-CVME-PBPS1:Lnk9Ch13", - ), + # pvname_fedigitizerchannels=dict( + # up="SAROP21-CVME-PBPS1:Lnk9Ch0", + # down="SAROP21-CVME-PBPS1:Lnk9Ch12", + # left="SAROP21-CVME-PBPS1:Lnk9Ch15", + # right="SAROP21-CVME-PBPS1:Lnk9Ch13", + # ), name="mon_opt_dev", module_name="eco.xdiagnostics.intensity_monitors", lazy=True, @@ -282,6 +299,8 @@ namespace.append_obj( "SARFE10-PPRM064", module_name="eco.xdiagnostics.profile_monitors", name="prof_fe", + in_target=3, + lazy=True, ) namespace.append_obj( @@ -290,6 +309,8 @@ namespace.append_obj( "SAROP11-PPRM066", module_name="eco.xdiagnostics.profile_monitors", name="prof_mirr_alv1", + in_target=3, + lazy=True, ) namespace.append_obj( @@ -298,6 +319,8 @@ namespace.append_obj( "SAROP21-PPRM094", module_name="eco.xdiagnostics.profile_monitors", name="prof_mirr1", + in_target=3, + lazy=True, ) namespace.append_obj( @@ -306,6 +329,8 @@ namespace.append_obj( "SAROP21-PPRM113", module_name="eco.xdiagnostics.profile_monitors", name="prof_mono", + in_target=3, + lazy=True, ) @@ -315,6 +340,8 @@ namespace.append_obj( "SAROP21-PPRM133", module_name="eco.xdiagnostics.profile_monitors", name="prof_opt", + in_target=3, + lazy=True, ) @@ -324,10 +351,15 @@ namespace.append_obj( "SAROP21-PPRM138", module_name="eco.xdiagnostics.profile_monitors", name="prof_att", + in_target=3, + lazy=True, ) namespace.append_obj( - "DownstreamDiagnostic", name="dsd", module_name="eco.xdiagnostics.dsd" + "DownstreamDiagnostic", + name="dsd", + module_name="eco.xdiagnostics.dsd", + lazy=True, ) namespace.append_obj( @@ -339,8 +371,14 @@ namespace.append_obj( lazy=True, ) namespace.append_obj( - "SolidTargetDetectorPBPS_new_assembly", - pvname="SARES20-DSDPBPS", + "SolidTargetDetectorPBPS", + "SARES20-DSDPBPS", + # diode_channels_raw={ + # "up": "", + # "down": "", + # "left": "", + # "right":"", + # }, module_name="eco.xdiagnostics.intensity_monitors", name="mon_dsd", lazy=True, @@ -1489,12 +1527,35 @@ class Xspect_EH55(Assembly): super().__init__(name=name) self._append(MotorRecord, "SARES20-MF1:MOT_15", name="x_crystal") self._append(MotorRecord, "SARES20-MF1:MOT_16", name="y_crystal") - # self._append(SmaractRecord,'SARES20-MF1:MOT_16',name='theta_crystal') + self._append(SmaractRecord, "SARES23:ESB17", name="theta_crystal") namespace.append_obj(Xspect_EH55, name="xspect_bernina", lazy=True) +namespace.append_obj( + "SlitBladesGeneral", + name="slit_cleanup_air", + def_blade_up={ + "args": [MotorRecord, "SARES20-MF1:MOT_10"], + "kwargs": {"is_psi_mforce": True}, + }, + def_blade_down={ + "args": [MotorRecord, "SARES20-MF1:MOT_11"], + "kwargs": {"is_psi_mforce": True}, + }, + def_blade_left={ + "args": [MotorRecord, "SARES20-MF1:MOT_13"], + "kwargs": {"is_psi_mforce": True}, + }, + def_blade_right={ + "args": [MotorRecord, "SARES20-MF1:MOT_12"], + "kwargs": {"is_psi_mforce": True}, + }, + module_name="eco.xoptics.slits", + lazy=True, +) + #### pgroup specific appending, might be temporary at this location #### # namespace.append_obj("Xom", module_name="xom", name="xom", lazy=True) @@ -1535,6 +1596,8 @@ namespace.append_obj(Xspect_EH55, name="xspect_bernina", lazy=True) # "desc": "DCM Monochromator", # "type": "eco.xoptics.dcm:Double_Crystal_Mono", # }, + + def pgroup2name(pgroup): tp = "/sf/bernina/exp/" d = Path(tp) diff --git a/eco/devices_general/motors.py b/eco/devices_general/motors.py index ec7950e..38cb1fc 100755 --- a/eco/devices_general/motors.py +++ b/eco/devices_general/motors.py @@ -433,6 +433,7 @@ class MotorRecord(Assembly): # alias_fields={"readback": "RBV"}, alias_fields={}, backlash_definition=False, + is_psi_mforce=False, schneider_config=None, expect_bad_limits=True, ): @@ -546,8 +547,38 @@ class MotorRecord(Assembly): is_setting=True, ) - if expect_bad_limits: - self.check_bad_limits() + if is_psi_mforce: + controller_base, tmp = self.pvname.split(":") + channel = int(tmp.split("_")[1]) + mforce_base = controller_base + ":" + str(channel) + + self._append( + AdjustablePv, + mforce_base + "_RC", + name="run_current", + is_setting=True, + ) + self._append( + AdjustablePv, + mforce_base + "_HC", + name="hold_current", + is_setting=True, + ) + self._append( + AdjustablePv, + mforce_base + "_set", + name="m_code_set", + is_setting=False, + is_display=False, + ) + self._append( + AdjustablePv, + mforce_base + "_get", + name="m_code_get", + is_setting=False, + is_display=False, + ) + if schneider_config: pv_base, port = schneider_config self._append( @@ -558,6 +589,8 @@ class MotorRecord(Assembly): is_setting=True, is_display=False, ) + if expect_bad_limits: + self.check_bad_limits() def check_bad_limits(self, abs_set_value=2**53): ll, hl = self.get_limits() @@ -870,6 +903,7 @@ class SmaractRecord(Assembly): # alias_fields={"readback": "RBV"}, alias_fields={}, backlash_definition=False, + expect_bad_limits=True, ): super().__init__(name=name) # self.settings.append(self) @@ -1013,6 +1047,13 @@ class SmaractRecord(Assembly): name="backlash_fraction", is_setting=True, ) + if expect_bad_limits: + self.check_bad_limits() + + def check_bad_limits(self, abs_set_value=2**53): + ll, hl = self.get_limits() + if ll == 0 and hl == 0: + self.set_limits(-abs_set_value, abs_set_value) def home(self): self.home_forward(1) diff --git a/eco/dummy/config.py b/eco/dummy/config.py index 3e130a8..555e1fb 100755 --- a/eco/dummy/config.py +++ b/eco/dummy/config.py @@ -373,19 +373,7 @@ components = [ # "type": "tof:jet", # "kwargs": {}, # }, - { - "args": [], - "name": "xeye", - "z_und": 142, - "desc": "Mobile X-ray eye in Bernina hutch", - "type": "eco.xdiagnostics.profile_monitors:Bernina_XEYE", - "kwargs": { - "zoomstage_pv": config["xeye"]["zoomstage_pv"], - "camera_pv": config["xeye"]["camera_pv"], - "bshost": "sf-daqsync-01.psi.ch", - "bsport": 11151, - }, - }, + { "args": ["SARES20-CAMS142-M1"], "name": "cam_sample_sideview", diff --git a/eco/timing/event_timing_new_new.py b/eco/timing/event_timing_new_new.py index cb1fa71..633cb35 100644 --- a/eco/timing/event_timing_new_new.py +++ b/eco/timing/event_timing_new_new.py @@ -491,14 +491,14 @@ class EvrOutput(Assembly): def pulserA(self): try: return self._pulsers[self.pulserA_number.get_current_value()] - except IndexError: + except (IndexError, TypeError): return DummyPulser() @property def pulserB(self): try: return self._pulsers[self.pulserA_number.get_current_value()] - except IndexError: + except (IndexError, TypeError): return DummyPulser() diff --git a/eco/xdiagnostics/intensity_monitors.py b/eco/xdiagnostics/intensity_monitors.py index 198330e..7af01a5 100755 --- a/eco/xdiagnostics/intensity_monitors.py +++ b/eco/xdiagnostics/intensity_monitors.py @@ -118,6 +118,13 @@ class CalibrationRecord(Assembly): is_setting=True, is_display=True, ) + self._append( + AdjustablePv, + self.pvbase + ".J", + name="const_J", + is_setting=True, + is_display=True, + ) self._append( AdjustablePv, self.pvbase + ".CALC", @@ -127,6 +134,11 @@ class CalibrationRecord(Assembly): ) +# class SolidTargetDetectorPBPSMonOpt(SolidTargetDetectorPBPS): +# def __init__(self, *args, **kwargs): +# ... + + class SolidTargetDetectorPBPS(Assembly): def __init__( self, @@ -134,7 +146,7 @@ class SolidTargetDetectorPBPS(Assembly): # VME_crate=None, # pipeline=None, # link=None, - # channels={}, + diode_channels_raw={}, # ch_up=12, # ch_down=13, # ch_left=15, @@ -172,6 +184,32 @@ class SolidTargetDetectorPBPS(Assembly): DetectorPvDataStream, pvname + ":YPOS", name="ypos", is_setting=False ) + if diode_channels_raw: + self._append( + DetectorPvDataStream, + diode_channels_raw["up"], + name="signal_up_raw", + is_setting=False, + ) + self._append( + DetectorPvDataStream, + diode_channels_raw["down"], + name="signal_down_raw", + is_setting=False, + ) + self._append( + DetectorPvDataStream, + diode_channels_raw["left"], + name="signal_left_raw", + is_setting=False, + ) + self._append( + DetectorPvDataStream, + diode_channels_raw["right"], + name="signal_right_raw", + is_setting=False, + ) + # Calibration calculation record # Calibration @@ -197,144 +235,34 @@ class SolidTargetDetectorPBPS(Assembly): is_display=False, ) - # self._append( - # AdjustablePv, pvname + ":XPOS.INPD", name="calc_input_D", is_setting=True, is_display=False - # ) - - # self._append( - # AdjustablePv, pvname + ":XPOS.IE", name="calc_input_E", is_setting=True, is_display=False - - # self._append( - # AdjustablePv, pvname + ":XPOS.IF", name="calc_input_F", is_setting=True, is_display=False - # ) - # self._append( - # AdjustablePv, pvname + ":XPOS.INPG", name="calc_input_G", is_setting=True, is_display=False - # ) - # self._append( - # AdjustablePv, pvname + ":XPOS.INPH", name="calc_input_H", is_setting=True, is_display=False - # ) - # self._append( - # AdjustablePv, pvname + ":XPOS.CALC", name="calc_function", is_setting=True, is_display=False - # ) - - # # Intensity - # # Set channels - # # Input data - # ep.PV(Devive_prefix+'INTENSITY.INPA').put(bytes(channels[0], "utf8")) - # ep.PV(Devive_prefix+'INTENSITY.INPB').put(bytes(channels[1], "utf8")) - # ep.PV(Devive_prefix+'INTENSITY.INPC').put(bytes(channels[2], "utf8")) - # ep.PV(Devive_prefix+'INTENSITY.INPD').put(bytes(channels[3], "utf8")) - # # Calibration values - # ep.PV(Devive_prefix+'INTENSITY.E').put(bytes(str(norm_diodes[0,0]), "utf8")) - # ep.PV(Devive_prefix+'INTENSITY.F').put(bytes(str(norm_diodes[0,1]), "utf8")) - # ep.PV(Devive_prefix+'INTENSITY.G').put(bytes(str(norm_diodes[0,2]), "utf8")) - # ep.PV(Devive_prefix+'INTENSITY.H').put(bytes(str(norm_diodes[0,3]), "utf8")) - # # Calculation - # ep.PV(Devive_prefix+'INTENSITY.CALC').put(bytes("A*E+B*F+C*G+D*H", "utf8")) - - # # XPOS - # # Set channels - # ep.PV(Devive_prefix+'XPOS.INPA').put(bytes(channels[2], "utf8")) - # ep.PV(Devive_prefix+'XPOS.INPB').put(bytes(channels[3], "utf8")) - # # Threshold value - # ep.PV(Devive_prefix+'XPOS.D').put(bytes(str(0.2), "utf8")) - # # Diode calibration value - # ep.PV(Devive_prefix+'XPOS.E').put(bytes(str(norm_diodes[0,2]), "utf8")) - # ep.PV(Devive_prefix+'XPOS.F').put(bytes(str(norm_diodes[0,3]), "utf8")) - # # Null value - # ep.PV(Devive_prefix+'XPOS.G').put(bytes(str(0), "utf8")) - # # Position calibration value - # ep.PV(Devive_prefix+'XPOS.I').put(bytes(str((Scan_x_range[1]-Scan_x_range[0])/ np.diff(scan_x_norm).mean()), "utf8")) - # # Intensity threshold value - # ep.PV(Devive_prefix+'XPOS.INPJ').put(bytes(Devive_prefix+'INTENSITY', "utf8")) - # # Calculation - # ep.PV(Devive_prefix+'XPOS.CALC').put(bytes("J Date: Wed, 7 Sep 2022 08:43:13 +0200 Subject: [PATCH 15/52] fixed code for setting the position of the slit in SlitBladesGeneral --- eco/xoptics/slits.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eco/xoptics/slits.py b/eco/xoptics/slits.py index 2d18175..959747b 100755 --- a/eco/xoptics/slits.py +++ b/eco/xoptics/slits.py @@ -841,10 +841,10 @@ class SlitBladesGeneral(Assembly): return tuple([tx + self.vpos.get_current_value() for tx in [-x / 2, x / 2]]) def sethpos(x): - return tuple([tx + self.hgap.get_current_value() for tx in [-x / 2, x / 2]]) + return tuple([x + tx for tx in [-self.hgap.get_current_value()/2, self.hgap.get_current_value()/2]]) def setvpos(x): - return tuple([tx + self.vgap.get_current_value() for tx in [-x / 2, x / 2]]) + return tuple([x + tx for tx in [-self.vgap.get_current_value()/2, self.vgap.get_current_value()/2]]) self._append( AdjustableVirtual, From e7682b4c6bec5bc717f2e3bdcbd2d6f69c74d395 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Wed, 7 Sep 2022 10:22:07 +0200 Subject: [PATCH 16/52] fixes --- eco/xoptics/att_usd.py | 2 ++ eco/xoptics/reflaser.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/eco/xoptics/att_usd.py b/eco/xoptics/att_usd.py index a7189e9..5cd8940 100644 --- a/eco/xoptics/att_usd.py +++ b/eco/xoptics/att_usd.py @@ -290,6 +290,8 @@ class Att_usd(Assembly): def _updateE(self, energy=None, check_once=False): while not energy: energy = PV("SAROP21-ARAMIS:ENERGY").value + if np.isnan(energy): + energy = PV("SARUN:FELPHOTENE").value*1000 if energy < self.E_min: energy = None print( diff --git a/eco/xoptics/reflaser.py b/eco/xoptics/reflaser.py index 72f3555..c92e48f 100644 --- a/eco/xoptics/reflaser.py +++ b/eco/xoptics/reflaser.py @@ -7,7 +7,7 @@ from ..elements.assembly import Assembly class RefLaser_Aramis(Assembly): - def __init__(self, Id, elog=None, name=None, inpos=-13.7, outpos=-5): + def __init__(self, Id, elog=None, name=None, inpos=-19, outpos=-5): super().__init__(name=name) self.Id = Id self.elog = elog From 5f0b3852a7170ee031247d572a8a2232045bc638 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Thu, 8 Sep 2022 09:53:16 +0200 Subject: [PATCH 17/52] fix camera --- eco/bernina/bernina.py | 17 +++++++++++++---- eco/devices_general/cameras_swissfel.py | 2 +- eco/xdiagnostics/profile_monitors.py | 8 ++++---- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 49968e4..56c99bf 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -4,7 +4,7 @@ from eco.acquisition.scan import NumpyEncoder from eco.elements.adjustable import AdjustableFS from eco.elements.adjustable import AdjustableVirtual from eco.loptics.bernina_experiment import DelayCompensation - +from eco.devices_general.cameras_swissfel import CameraBasler # from eco.endstations.bernina_sample_environments import Organic_crystal_breadboard_old from eco.motion.smaract import SmaractController from .config import components @@ -1525,9 +1525,18 @@ except: class Xspect_EH55(Assembly): def __init__(self, name="xspect_bernina"): super().__init__(name=name) - self._append(MotorRecord, "SARES20-MF1:MOT_15", name="x_crystal") - self._append(MotorRecord, "SARES20-MF1:MOT_16", name="y_crystal") - self._append(SmaractRecord, "SARES23:ESB17", name="theta_crystal") + self._append( + MotorRecord, "SARES20-MF1:MOT_15", name="x_crystal", is_setting=True + ) + self._append( + MotorRecord, "SARES20-MF1:MOT_16", name="y_crystal", is_setting=True + ) + self._append( + SmaractRecord, "SARES23:ESB17", name="theta_crystal", is_setting=True + ) + self._append( + CameraBasler,"SARES20-CAMS142-M3",name="camera_bsss", is_display=False, is_setting=False + ) namespace.append_obj(Xspect_EH55, name="xspect_bernina", lazy=True) diff --git a/eco/devices_general/cameras_swissfel.py b/eco/devices_general/cameras_swissfel.py index 050b2a9..555141d 100644 --- a/eco/devices_general/cameras_swissfel.py +++ b/eco/devices_general/cameras_swissfel.py @@ -233,7 +233,7 @@ class CameraBasler(Assembly): ) self._append( AdjustablePv, - self.pvname + ":BINY", + self.pvname + ":BINX", name="_binx", is_setting=True, is_display=False, diff --git a/eco/xdiagnostics/profile_monitors.py b/eco/xdiagnostics/profile_monitors.py index 28602d5..4f1f029 100755 --- a/eco/xdiagnostics/profile_monitors.py +++ b/eco/xdiagnostics/profile_monitors.py @@ -179,18 +179,18 @@ class ProfKbBernina(Assembly): def movein(self, wait=False): ch = self.mirror_in.set_target_value(1) try: - self.target_stages.presets.movein() + self.presets.movein() except: - print("No movein preset found for target stages.") + print("No movein preset found for prof_kb.") if wait: ch.wait() def moveout(self, wait=False): ch = self.mirror_in.set_target_value(0) try: - self.target_stages.presets.moveout() + self.presets.moveout() except: - print("No moveout preset found for target stages.") + print("No moveout preset found for prof_kb.") if wait: ch.wait() From 536329a595db631e82558b6172107f0578e5800f Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Wed, 14 Sep 2022 11:45:33 +0200 Subject: [PATCH 18/52] fixes --- eco/acquisition/daq_client.py | 4 + eco/acquisition/scan.py | 1 + eco/bernina/bernina.py | 196 ++++++++++++++++++++++++++++------ eco/detector/jungfrau.py | 124 ++++++++++++++++++++- eco/devices_general/wago.py | 21 +++- eco/elements/assembly.py | 30 ++++-- 6 files changed, 332 insertions(+), 44 deletions(-) diff --git a/eco/acquisition/daq_client.py b/eco/acquisition/daq_client.py index 215b4de..1766eb5 100644 --- a/eco/acquisition/daq_client.py +++ b/eco/acquisition/daq_client.py @@ -23,6 +23,7 @@ class Daq(Assembly): channels_BSCAM=None, channels_CA=None, config_JFs=None, + rate_multiplicator=None, name=None, ): super().__init__(name=name) @@ -54,6 +55,8 @@ class Daq(Assembly): self.name = name self._default_file_path = None + self.rate_multiplicator = rate_multiplicator + def acquire(self, file_name=None, Npulses=100, acq_pars={}): print(file_name, Npulses) acquisition = Acquisition( @@ -164,6 +167,7 @@ class Daq(Assembly): parameters["directory_name"] = directory_relative.as_posix() parameters["pgroup"] = pgroup + parameters["rate_multiplicator"] = self.rate_multiplicator # print("----- debug info ----->\n", parameters, "\n<----- debug info -----") response = validate_response( requests.post( diff --git a/eco/acquisition/scan.py b/eco/acquisition/scan.py index aaa9891..d0ad0a6 100755 --- a/eco/acquisition/scan.py +++ b/eco/acquisition/scan.py @@ -94,6 +94,7 @@ class Scan: self._checker_sleep_time = checker_sleep_time self._elog = elog self.run_number = run_number + self.remaining_tasks = [] self.callbacks_end_scan = callbacks_end_scan print(f"Scan info in file {self.scan_info_filename}.") for adj in self.adjustables: diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 56c99bf..7820364 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -1,10 +1,12 @@ import json from pathlib import Path +from threading import Thread from eco.acquisition.scan import NumpyEncoder from eco.elements.adjustable import AdjustableFS from eco.elements.adjustable import AdjustableVirtual from eco.loptics.bernina_experiment import DelayCompensation from eco.devices_general.cameras_swissfel import CameraBasler + # from eco.endstations.bernina_sample_environments import Organic_crystal_breadboard_old from eco.motion.smaract import SmaractController from .config import components @@ -745,6 +747,7 @@ namespace.append_obj( pulse_id_adj="SLAAR21-LTIM01-EVR0:RX-PULSEID", event_master=event_master, detectors_event_code=50, + rate_multiplicator=4, name="daq", module_name="eco.acquisition.daq_client", lazy=True, @@ -768,6 +771,13 @@ namespace.append_obj( ) +def _wait_for_tasks(scan): + print("checking remaining tasks from previous scan ...") + for task in scan.remaining_tasks: + task.join() + print("... done.") + + def _append_namesace_status_to_scan(scan, daq=daq, namespace=namespace): namespace_status = namespace.get_status(base=None) stat = {"status_run_start": namespace_status} @@ -795,16 +805,40 @@ def _write_namespace_status_to_scan(scan, daq=daq, namespace=namespace): pgroup=pgroup, run_number=runno, ) - print("################") + print("####### transfer status #######") print(response.json()) - print("################") + print("###############################") + scan.scan_info["scan_parameters"]["status"] = "aux/status.json" -def _append_namespace_aliases_to_scan(scan): - scan.scan_info["scan_parameters"]["namespace_aliases"] = namespace.alias.get_all() +def _write_namespace_aliases_to_scan(scan, daq=daq): + namespace_aliases = namespace.alias.get_all() + runno = daq.get_last_run_number() + pgroup = daq.pgroup + tmpdir = Path(f"/sf/bernina/data/{pgroup}/res/tmp/aliases_run{runno:04d}") + tmpdir.mkdir(exist_ok=True, parents=True) + aliasfile = tmpdir / Path("aliases.json") + if not Path(aliasfile).exists(): + with open(aliasfile, "w") as f: + json.dump(namespace_aliases, f, sort_keys=True, cls=NumpyEncoder, indent=4) + else: + with open(aliasfile, "r+") as f: + f.seek(0) + json.dump(namespace_aliases, f, sort_keys=True, cls=NumpyEncoder, indent=4) + f.truncate() + response = daq.append_aux( + aliasfile.resolve().as_posix(), + pgroup=pgroup, + run_number=runno, + ) + print("####### transfer aliases #######") + print(response.json()) + print("################################") + scan.scan_info["scan_parameters"]["aliases"] = "aux/aliases.json" def _message_end_scan(scan): + print(f"Finished run {scan.run_number}.") e = pyttsx3.init() e.say(f"Finished run {scan.run_number}.") e.runAndWait() @@ -836,6 +870,8 @@ def _create_general_run_info(scan, daq=daq): def _copy_scan_info_to_raw(scan, daq=daq): + scan.writeScanInfo() + # get data that should come later from api or similar. run_directory = list( Path(f"/sf/bernina/data/{daq.pgroup}/raw").glob(f"run{scan.run_number:04d}*") @@ -876,32 +912,38 @@ from eco.detector import Jungfrau def _copy_selected_JF_pedestals_to_raw(scan, daq=daq): - runno = daq.get_last_run_number() - pgroup = daq.pgroup - for jf_id in daq.channels["channels_JF"](): - jf = Jungfrau(jf_id, name="noname", pgroup_adj=config_bernina.pgroup) - print( - f"Copying {jf_id} pedestal to run {runno} in the raw directory of {pgroup}." - ) - response = daq.append_aux( - jf.get_present_pedestal_filename_in_run(intempdir=True), - pgroup=pgroup, - run_number=runno, - ) - print( - f"Status: {response.json()['status']} Message: {response.json()['message']}" - ) - print( - f"Copying {jf_id} gainmap to run {runno} in the raw directory of {pgroup}." - ) - response = daq.append_aux( - jf.get_present_gain_filename_in_run(intempdir=True), - pgroup=pgroup, - run_number=runno, - ) - print( - f"Status: {response.json()['status']} Message: {response.json()['message']}" - ) + def copy_to_aux(daq): + runno = daq.get_last_run_number() + pgroup = daq.pgroup + + for jf_id in daq.channels["channels_JF"](): + jf = Jungfrau(jf_id, name="noname", pgroup_adj=config_bernina.pgroup) + print( + f"Copying {jf_id} pedestal to run {runno} in the raw directory of {pgroup}." + ) + response = daq.append_aux( + jf.get_present_pedestal_filename_in_run(intempdir=True), + pgroup=pgroup, + run_number=runno, + ) + print( + f"Status: {response.json()['status']} Message: {response.json()['message']}" + ) + print( + f"Copying {jf_id} gainmap to run {runno} in the raw directory of {pgroup}." + ) + + response = daq.append_aux( + jf.get_present_gain_filename_in_run(intempdir=True), + pgroup=pgroup, + run_number=runno, + ) + print( + f"Status: {response.json()['status']} Message: {response.json()['message']}" + ) + + scan.remaining_tasks.append(Thread(target=copy_to_aux, args=[daq])) + scan.remaining_tasks[-1].start() def _increment_daq_run_number(scan, daq=daq): @@ -927,13 +969,15 @@ def _increment_daq_run_number(scan, daq=daq): callbacks_start_scan = [] callbacks_start_scan = [lambda scan: namespace.init_all(silent=False)] +callbacks_start_scan.append(_wait_for_tasks) callbacks_start_scan.append(_append_namesace_status_to_scan) -callbacks_start_scan.append(_append_namespace_aliases_to_scan) callbacks_start_scan.append(_increment_daq_run_number) -callbacks_end_scan = [_message_end_scan] +callbacks_end_scan = [] callbacks_end_scan.append(_write_namespace_status_to_scan) +callbacks_end_scan.append(_write_namespace_aliases_to_scan) callbacks_end_scan.append(_copy_scan_info_to_raw) callbacks_end_scan.append(_copy_selected_JF_pedestals_to_raw) +callbacks_end_scan.append(_message_end_scan) # >>>> Extract for run_table and elog @@ -1535,7 +1579,11 @@ class Xspect_EH55(Assembly): SmaractRecord, "SARES23:ESB17", name="theta_crystal", is_setting=True ) self._append( - CameraBasler,"SARES20-CAMS142-M3",name="camera_bsss", is_display=False, is_setting=False + CameraBasler, + "SARES20-CAMS142-M3", + name="camera_bsss", + is_display=False, + is_setting=False, ) @@ -1565,6 +1613,88 @@ namespace.append_obj( lazy=True, ) + +from eco.devices_general.wago import AnalogOutput +from eco.detector import Jungfrau +from eco.timing.event_timing_new_new import EvrOutput +from eco.devices_general.digitizers import DigitizerIoxosBoxcarChannel + + +class Tapedrive(Assembly): + def __init__(self, name=None): + super().__init__(name=name) + self._append( + AdjustablePv, "KERNVARIABLES:DELAYBETWEENXFELANDLASER", name="delay" + ) + self._append(SmaractRecord, "SARES23:ESB18", name="freespace_pitch") + self._append(SmaractRecord, "SARES23:ESB13", name="freespace_roll") + self._append(MotorRecord, "SARES20-MF1:MOT_7", name="rot_analyzer_hor") + self._append(MotorRecord, "SARES20-MF1:MOT_8", name="rot_analyzer_ver") + + self._append(AnalogOutput, "SARES20-CWAG-GPS01:DAC01", name="shutter1") + self._append(AnalogOutput, "SARES20-CWAG-GPS01:DAC02", name="shutter2") + self._append(AnalogOutput, "SARES20-CWAG-GPS01:DAC03", name="shutter3") + self._append(AnalogOutput, "SARES20-CWAG-GPS01:DAC04", name="shutter4") + + self._append( + EvrOutput, + f"SARES20-CVME-01-EVR0:RearUniv0", + pulsers=evr.pulsers, + name=f"trigger_patch1_bnc6", + is_setting=True, + # is_display="recursive", + ) + self._append( + EvrOutput, + f"SARES20-CVME-01-EVR0:RearUniv1", + pulsers=evr.pulsers, + name=f"trigger_patch2_bnc6", + is_setting=True, + # is_display="recursive", + ) + + self._append( + Jungfrau, + "JF07T32V01", + config_adj=daq.config_JFs, + pgroup_adj=config_bernina.pgroup, + name="det_diff", + is_setting=True, + is_status=True, + # is_display="recursive", + ) + self._append( + Jungfrau, + "JF05T01V01", + config_adj=daq.config_JFs, + pgroup_adj=config_bernina.pgroup, + name="det_spect", + is_setting=True, + is_status=True, + # is_display="recursive", + ) + self._append( + Jungfrau, + "JF03T01V01", + config_adj=daq.config_JFs, + pgroup_adj=config_bernina.pgroup, + name="det_imon", + is_setting=True, + is_status=True, + # is_display="recursive", + ) + + self._append( + DigitizerIoxosBoxcarChannel, "SARES20-LSCP9-FNS:CH1", name="diode_1" + ) + self._append( + DigitizerIoxosBoxcarChannel, "SARES20-LSCP9-FNS:CH2", name="diode_2" + ) + + +namespace.append_obj(Tapedrive, name="tapedrive", lazy=True) + + #### pgroup specific appending, might be temporary at this location #### # namespace.append_obj("Xom", module_name="xom", name="xom", lazy=True) diff --git a/eco/detector/jungfrau.py b/eco/detector/jungfrau.py index 59a565d..6f3c3a3 100644 --- a/eco/detector/jungfrau.py +++ b/eco/detector/jungfrau.py @@ -1,6 +1,8 @@ import shutil from tkinter import W -from ..elements.adjustable import AdjustableVirtual, AdjustableGetSet + +from eco.base.adjustable import Adjustable +from ..elements.adjustable import AdjustableFS, AdjustableVirtual, AdjustableGetSet from ..epics.adjustable import AdjustablePv from ..elements.assembly import Assembly from ..aliases import Alias @@ -18,6 +20,7 @@ class Jungfrau(Assembly): trigger_off=255, broker_address="http://sf-daq:10002", pgroup_adj=None, + config_adj=None, name=None, ): super().__init__(name=name) @@ -79,6 +82,16 @@ class Jungfrau(Assembly): name="gain_file_in_run", is_display=True, ) + if config_adj: + self._append( + JungfrauDaqConfig, + jf_id, + config_adj, + name="config_daq", + is_setting=True, + is_status=True, + is_display="recursive", + ) def _set_trigger_enable(self, value): if value: @@ -168,3 +181,112 @@ class Jungfrau(Assembly): # return requests.post( # f"{self.broker_address}/take_pedestal", json=parameters # ).json() + + +class JungfrauDaqConfig(Assembly): + def __init__(self, jf_id, jf_daq_cfg: Adjustable, name=None): + super().__init__(name=name) + self._jf_id = jf_id + self._jf_daq_cfg = jf_daq_cfg + cfg = self._jf_daq_cfg.get_current_value() + if self._jf_id not in cfg.keys(): + cfg[self._jf_id] = {} + self._jf_daq_cfg.set_target_value(cfg).wait() + + self._append( + AdjustableGetSet, + self._get_adc_to_energy, + self._set_adc_to_energy, + name="convert_adc_to_energy", + is_display=True, + is_setting=True, + ) + self._append( + AdjustableGetSet, + self._get_compressed_bitshuffle, + self._set_compressed_bitshuffle, + name="compress_bitshuffle", + is_display=True, + is_setting=True, + ) + self._append( + AdjustableGetSet, + self._get_keep_raw_data, + self._set_keep_raw_data, + name="keep_raw_data", + is_display=True, + is_setting=True, + ) + self._append( + AdjustableGetSet, + self._get_large_pixel_processing, + self._set_large_pixel_processing, + name="large_pixel_processing", + is_display=True, + is_setting=True, + ) + + def _get_adc_to_energy(self, *args): + try: + return self._jf_daq_cfg.get_current_value()[self._jf_id]["adc_to_energy"] + except KeyError: + return False + + def _set_adc_to_energy(self, value): + if value: + cfg = self._jf_daq_cfg.get_current_value() + cfg[self._jf_id]["adc_to_energy"] = True + self._jf_daq_cfg.set_target_value(cfg).wait() + else: + cfg = self._jf_daq_cfg.get_current_value() + cfg[self._jf_id]["adc_to_energy"] = False + self._jf_daq_cfg.set_target_value(cfg).wait() + + def _get_compressed_bitshuffle(self, *args): + try: + return self._jf_daq_cfg.get_current_value()[self._jf_id]["compression"] + except KeyError: + return False + + def _set_compressed_bitshuffle(self, value): + if value: + cfg = self._jf_daq_cfg.get_current_value() + cfg[self._jf_id]["compression"] = True + self._jf_daq_cfg.set_target_value(cfg).wait() + else: + cfg = self._jf_daq_cfg.get_current_value() + cfg[self._jf_id]["compression"] = False + self._jf_daq_cfg.set_target_value(cfg).wait() + + def _get_keep_raw_data(self, *args): + try: + return not self._jf_daq_cfg.get_current_value()[self._jf_id][ + "remove_raw_file" + ] + except KeyError: + # raise Exception("unclear what the default for keeping raw files is!") + return None + + def _set_keep_raw_data(self, value): + if value: + cfg = self._jf_daq_cfg.get_current_value() + cfg[self._jf_id]["remove_raw_file"] = False + self._jf_daq_cfg.set_target_value(cfg).wait() + else: + cfg = self._jf_daq_cfg.get_current_value() + cfg[self._jf_id]["remove_raw_file"] = True + self._jf_daq_cfg.set_target_value(cfg).wait() + + def _get_large_pixel_processing(self, *args): + try: + return self._jf_daq_cfg.get_current_value()[self._jf_id][ + "double_pixels_action" + ] + except KeyError: + # raise Exception("unclear what the default for double pixels is!") + return None + + def _set_large_pixel_processing(self, value): + cfg = self._jf_daq_cfg.get_current_value() + cfg[self._jf_id]["double_pixels_action"] = value + self._jf_daq_cfg.set_target_value(cfg).wait() diff --git a/eco/devices_general/wago.py b/eco/devices_general/wago.py index 687dd4d..c4ad1c5 100644 --- a/eco/devices_general/wago.py +++ b/eco/devices_general/wago.py @@ -1,6 +1,11 @@ from eco.elements.assembly import Assembly from eco.epics.detector import DetectorPvData -from eco.epics.adjustable import AdjustablePvString, AdjustablePv +from eco.epics.adjustable import ( + AdjustablePvString, + AdjustablePv, + spec_convenience, + tweak_option, +) class AnalogInput(Assembly): @@ -44,6 +49,8 @@ class WagoAnalogInputs(Assembly): self._append(AnalogInput, pvbase + f":ADC{n:02d}", name=f"ch{n:d}") +@spec_convenience +@tweak_option class AnalogOutput(Assembly): def __init__(self, pvname, name=None): super().__init__(name=name) @@ -51,7 +58,6 @@ class AnalogOutput(Assembly): self._append( AdjustablePv, self.pvname, - self.pvname + "_RB", name="value", is_setting=True, is_display=True, @@ -81,6 +87,9 @@ class AnalogOutput(Assembly): def get_current_value(self): return self.value.get_current_value() + def set_target_value(self, *args, **kwargs): + return self.value.set_target_value(*args, **kwargs) + def __call__(self, *args): if args: self.value.set_target_Value(*args).wait() @@ -93,4 +102,10 @@ class WagoAnalogOutputs(Assembly): super().__init__(name=name) self.pvbase = pvbase for n in range(1, 9): - self._append(AnalogOutput, pvbase + f":DAC{n:02d}", name=f"ch{n:d}") + self._append( + AnalogOutput, + pvbase + f":DAC{n:02d}", + name=f"ch{n:d}", + is_setting=True, + is_display=True, + ) diff --git a/eco/elements/assembly.py b/eco/elements/assembly.py index b4e4445..f035d45 100644 --- a/eco/elements/assembly.py +++ b/eco/elements/assembly.py @@ -201,20 +201,36 @@ class Assembly: tab = [] for to in stats: name = to.alias.get_full_name(base=self) - value = to.get_current_value() + is_adjustable = isinstance(to, Adjustable) - if is_adjustable: - typechar = "✏️" - else: - typechar = "👁️" is_detector = isinstance(to, Detector) + typechar = "" + if is_adjustable: + typechar += "✏️" + elif is_detector: + typechar += "👁️" + if hasattr(to, "settings_collection"): + typechar += " ↳" + + try: + value = to.get_current_value() + except AttributeError: + if hasattr(to, "settings_collection"): + value = "\x1b[3mhas lower level items\x1b[0m" + if isinstance(value, Enum): value = f"{value.value} ({value.name})" try: - unit = to.unit() + unit = to.unit.get_current_value() except: unit = None - tab.append([".".join([main_name, name]), value, unit, typechar]) + try: + description = to.description.get_current_value() + except: + description = None + tab.append( + [".".join([main_name, name]), value, unit, typechar, description] + ) s = tabulate(tab) return s From bba65d0756905bdb76f58a78df046f271e2372f8 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Wed, 14 Sep 2022 16:37:51 +0200 Subject: [PATCH 19/52] changed pulse picker methods open/close to not change the trigger source to 62 and 63 --- eco/xoptics/pp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eco/xoptics/pp.py b/eco/xoptics/pp.py index c840e17..6e7aeb4 100755 --- a/eco/xoptics/pp.py +++ b/eco/xoptics/pp.py @@ -38,12 +38,12 @@ class Pulsepick: def open(self): self._openclose.put(1) - self._evrsrc.put(62) + #self._evrsrc.put(62) print("Opened Pulse Picker") def close(self): self._openclose.put(0) - self._evrsrc.put(62) + #self._evrsrc.put(62) print("Closed Pulse Picker") def trigger(self): From caa5e5332eaab84bbdd57502f2699bf2985c9145 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Mon, 19 Sep 2022 10:24:07 +0200 Subject: [PATCH 20/52] changes after kern --- eco/acquisition/scan.py | 14 +++++++++++--- eco/bernina/bernina.py | 38 ++++++++++++++++++++++++++++++++++---- eco/detector/jungfrau.py | 26 +++++++++++++++++++++++--- eco/xoptics/dcm.py | 3 ++- 4 files changed, 70 insertions(+), 11 deletions(-) diff --git a/eco/acquisition/scan.py b/eco/acquisition/scan.py index d0ad0a6..a702a52 100755 --- a/eco/acquisition/scan.py +++ b/eco/acquisition/scan.py @@ -1,3 +1,4 @@ +from numbers import Number import os import json import numpy as np @@ -65,10 +66,16 @@ class Scan: raise ScanNameError self.Nsteps = len(values) self._run_table = run_table - self.pulses_per_step = Npulses + if not isinstance(Npulses, Number): + if not len(Npulses) == len(values): + raise ValueError("steps for Number of pulses and values must match!") + self.pulses_per_step = Npulses + else: + self.pulses_per_step = [Npulses] * len(values) self.adjustables = adjustables self.values_todo = values self.values_done = [] + self.pulses_done = [] self.readbacks = [] self.counterCallers = counterCallers self.fina = fina @@ -185,10 +192,10 @@ class Scan: "user_tag": self.fina, } acq = ctr.acquire( - file_name=fina, Npulses=self.pulses_per_step, acq_pars=acq_pars + file_name=fina, Npulses=self.pulses_per_step[0], acq_pars=acq_pars ) else: - acq = ctr.acquire(file_name=fina, Npulses=self.pulses_per_step) + acq = ctr.acquire(file_name=fina, Npulses=self.pulses_per_step[0]) acs.append(acq) filenames = [] for ta in acs: @@ -205,6 +212,7 @@ class Scan: else: tstepinfo = step_info self.values_done.append(self.values_todo.pop(0)) + self.pulses_done.append(self.pulses_per_step.pop(0)) self.readbacks.append(readbacks_step) self.appendScanInfo( values_step, readbacks_step, step_files=filenames, step_info=tstepinfo diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 7820364..d5313c9 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -747,7 +747,7 @@ namespace.append_obj( pulse_id_adj="SLAAR21-LTIM01-EVR0:RX-PULSEID", event_master=event_master, detectors_event_code=50, - rate_multiplicator=4, + rate_multiplicator=2, name="daq", module_name="eco.acquisition.daq_client", lazy=True, @@ -1008,10 +1008,14 @@ def _create_metadata_structure_start_scan(scan, run_table=run_table, elog=elog): f"id_motor_{n}": nId, } ) + if np.mean(np.diff(scan.pulses_per_step))<1: + pulses_per_step = scan.pulses_per_step[0] + else: + pulses_per_step = scan.pulses_per_step metadata.update( { "steps": len(scan.values_todo), - "pulses_per_step": scan.pulses_per_step, + "pulses_per_step": pulses_per_step, "counters": [daq.name for daq in scan.counterCallers], } ) @@ -1618,8 +1622,8 @@ from eco.devices_general.wago import AnalogOutput from eco.detector import Jungfrau from eco.timing.event_timing_new_new import EvrOutput from eco.devices_general.digitizers import DigitizerIoxosBoxcarChannel - - +from eco.elements.adjustable import AdjustableVirtual +import numpy as np class Tapedrive(Assembly): def __init__(self, name=None): super().__init__(name=name) @@ -1692,6 +1696,32 @@ class Tapedrive(Assembly): ) + self._append( + AdjustableFS, + "/photonics/home/gac-bernina/eco/configuration/p20231_mono_und_offset", + name="mono_und_calib", + default_value=[[6500,0],[7100,0]], + is_setting=True, + ) + + def en_set(en): + ofs = np.array(self.mono_und_calib()).T + fel_ofs = ofs[1][np.argmin(abs(ofs[0]-en))] + return en , en/1000 - fel_ofs + def en_get(monoen, felen): + return monoen + self._append( + AdjustableVirtual, + [mono, fel.aramis_photon_energy_undulators], + en_get, + en_set, + name="mono_und_energy", + ) + def add_mono_und_calibration(self): + mono_energy = mono.get_current_value() + fel_offset = mono.get_current_value() /1000 - fel.aramis_photon_energy_undulators.get_current_value() + self.mono_und_calib.mvr([[mono_energy,fel_offset]]) + namespace.append_obj(Tapedrive, name="tapedrive", lazy=True) diff --git a/eco/detector/jungfrau.py b/eco/detector/jungfrau.py index 6f3c3a3..261bcdc 100644 --- a/eco/detector/jungfrau.py +++ b/eco/detector/jungfrau.py @@ -225,6 +225,14 @@ class JungfrauDaqConfig(Assembly): is_display=True, is_setting=True, ) + self._append( + AdjustableGetSet, + self._get_rounding_factor, + self._set_rounding_factor, + name="rounding_factor_keV", + is_display=True, + is_setting=True, + ) def _get_adc_to_energy(self, *args): try: @@ -261,7 +269,7 @@ class JungfrauDaqConfig(Assembly): def _get_keep_raw_data(self, *args): try: return not self._jf_daq_cfg.get_current_value()[self._jf_id][ - "remove_raw_file" + "remove_raw_files" ] except KeyError: # raise Exception("unclear what the default for keeping raw files is!") @@ -270,11 +278,11 @@ class JungfrauDaqConfig(Assembly): def _set_keep_raw_data(self, value): if value: cfg = self._jf_daq_cfg.get_current_value() - cfg[self._jf_id]["remove_raw_file"] = False + cfg[self._jf_id]["remove_raw_files"] = False self._jf_daq_cfg.set_target_value(cfg).wait() else: cfg = self._jf_daq_cfg.get_current_value() - cfg[self._jf_id]["remove_raw_file"] = True + cfg[self._jf_id]["remove_raw_files"] = True self._jf_daq_cfg.set_target_value(cfg).wait() def _get_large_pixel_processing(self, *args): @@ -290,3 +298,15 @@ class JungfrauDaqConfig(Assembly): cfg = self._jf_daq_cfg.get_current_value() cfg[self._jf_id]["double_pixels_action"] = value self._jf_daq_cfg.set_target_value(cfg).wait() + + def _get_rounding_factor(self, *args): + try: + return self._jf_daq_cfg.get_current_value()[self._jf_id]["factor"] + except KeyError: + # raise Exception("unclear what the default for double pixels is!") + return None + + def _set_rounding_factor(self, value): + cfg = self._jf_daq_cfg.get_current_value() + cfg[self._jf_id]["factor"] = value + self._jf_daq_cfg.set_target_value(cfg).wait() diff --git a/eco/xoptics/dcm.py b/eco/xoptics/dcm.py index 497b1c0..808a8a4 100755 --- a/eco/xoptics/dcm.py +++ b/eco/xoptics/dcm.py @@ -358,7 +358,8 @@ class AlvraDCM_FEL: # self.IOCstatus = PV('ALVRA:running') # bool 0 running, 1 not running self._FELcoupling = PV("SGE-OP2E-ARAMIS:MODE_SP") # string "Off" or "e-beam" self._setEnergy = PV("SAROP11-ARAMIS:ENERGY_SP_USER") # float eV - self._getEnergy = PV("SAROP11-ARAMIS:ENERGY") # float eV + #self._getEnergy = PV("SAROP11-ARAMIS:ENERGY") # float eV + self._getEnergy = PV("SAROP21-ODCM098:ENERGY") # float eV self.ebeamEnergy = PV("SARCL02-MBND100:P-READ") # float MeV/c # self.ebeamEnergySP = PV('ALVRA:Energy_SP') # float MeV self.dcmStop = PV("SAROP11-ODCM105:STOP.PROC") # stop the DCM motors From 0287da40da051058e8348de4ace784206ce7f7a3 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Wed, 12 Oct 2022 14:53:43 +0200 Subject: [PATCH 21/52] updating mon_opt and after hua --- eco/bernina/bernina.py | 409 +++++++++--------- eco/bernina/config.py | 2 +- .../bernina_sample_environments.py | 1 - eco/xdiagnostics/intensity_monitors.py | 93 ++-- 4 files changed, 264 insertions(+), 241 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index d5313c9..fd36318 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -10,7 +10,8 @@ from eco.devices_general.cameras_swissfel import CameraBasler # from eco.endstations.bernina_sample_environments import Organic_crystal_breadboard_old from eco.motion.smaract import SmaractController from .config import components -from .config import config as config_berninamesp + +# from .config import config as config_berninamesp from ..utilities.config import Namespace from ..aliases import NamespaceCollection import pyttsx3 @@ -284,13 +285,16 @@ namespace.append_obj( namespace.append_obj( "SolidTargetDetectorPBPS", "SAROP21-PBPS133", - # pvname_fedigitizerchannels=dict( - # up="SAROP21-CVME-PBPS1:Lnk9Ch0", - # down="SAROP21-CVME-PBPS1:Lnk9Ch12", - # left="SAROP21-CVME-PBPS1:Lnk9Ch15", - # right="SAROP21-CVME-PBPS1:Lnk9Ch13", - # ), - name="mon_opt_dev", + channel_xpos="SLAAR21-LTIM01-EVR0:CALCX", + channel_ypos="SLAAR21-LTIM01-EVR0:CALCY", + channel_intensity="SLAAR21-LTIM01-EVR0:CALCI", + diode_channels_raw={ + "up": "SLAAR21-LSCP1-FNS:CH6:VAL_GET", + "down": "SLAAR21-LSCP1-FNS:CH7:VAL_GET", + "left": "SLAAR21-LSCP1-FNS:CH4:VAL_GET", + "right": "SLAAR21-LSCP1-FNS:CH5:VAL_GET", + }, + name="mon_opt", module_name="eco.xdiagnostics.intensity_monitors", lazy=True, ) @@ -747,7 +751,7 @@ namespace.append_obj( pulse_id_adj="SLAAR21-LTIM01-EVR0:RX-PULSEID", event_master=event_master, detectors_event_code=50, - rate_multiplicator=2, + rate_multiplicator=1, name="daq", module_name="eco.acquisition.daq_client", lazy=True, @@ -1008,7 +1012,7 @@ def _create_metadata_structure_start_scan(scan, run_table=run_table, elog=elog): f"id_motor_{n}": nId, } ) - if np.mean(np.diff(scan.pulses_per_step))<1: + if np.mean(np.diff(scan.pulses_per_step)) < 1: pulses_per_step = scan.pulses_per_step[0] else: pulses_per_step = scan.pulses_per_step @@ -1258,118 +1262,114 @@ namespace.append_obj( ) # ad hoc incoupling device -# class Incoupling(Assembly): -# def __init__(self, name=None): -# super().__init__(name=name) -# self._append( -# SmaractRecord, "SARES23:LIC13", name="mirr_table_pitch", is_setting=True -# ) -# self._append( -# SmaractRecord, "SARES23:LIC14", name="mirr_table_roll", is_setting=True -# ) -# # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) -# # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) -# # self._append(SmaractRecord, "SARES23:ESB17", name="rotation", is_setting=True) -# -# -# namespace.append_obj( -# Incoupling, -# lazy=True, -# name="las_inc", -# ) - - -class THz_in_air(Assembly): +class Incoupling(Assembly): def __init__(self, name=None): super().__init__(name=name) + self._append(SmaractRecord, "SARES23:ESB16", name="pitch", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB3", name="roll", is_setting=True) + # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) + # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) + # self._append(SmaractRecord, "SARES23:ESB17", name="rotation", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB4", name="eos_rot", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB12", name="eos_tilt", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB5", name="crystal_ROT", is_setting=True) - self._append(SmaractRecord, "SARES23:LIC15", name="ir_1_z", is_setting=True) - self._append(SmaractRecord, "SARES23:LIC13", name="ir_1_Ry", is_setting=True) - self._append(SmaractRecord, "SARES23:LIC14", name="ir_1_Rx", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB10", name="ir_2_Rx", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB7", name="ir_2_Ry", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB9", name="para_2_x", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB3", name="thz_mir_x", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB1", name="thz_mir_z", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB8", name="thz_mir_Ry", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB2", name="thz_mir_Rz", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB6", name="focus_z", is_setting=True) - self._append( - MotorRecord, - "SARES20-MF1:MOT_4", - name="focus_y", - is_setting=True, - is_display=True, - ) - self._append(SmaractRecord, "SARES23:ESB14", name="focus_x", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB13", name="focus_Rz", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB15", name="focus_Ry", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB11", name="focus_Rx", is_setting=True) - self._append(SmaractRecord, "SARES23:LIC18", name="thz_wp", is_setting=True) - self._append( - SmaractRecord, "SARES23:LIC16", name="delaystage_thz", is_setting=True - ) - self._append(DelayTime, self.delaystage_thz, name="delay_thz", is_setting=True) - self._append( - MotorRecord, - "SLAAR21-LMOT-M521:MOTOR_1", - name="delaystage_800_pump", - is_setting=True, - ) - self._append( - DelayTime, self.delaystage_800_pump, name="delay_800_pump", is_setting=True - ) - self._append( - AdjustableFS, - "/photonics/home/gac-bernina/eco/configuration/combined_delta", - name="combined_delta", - default_value=0, - is_setting=True, - ) - self.delay_thz = DelayTime(self.delaystage_thz, name="delay_thz") - self._append( - AdjustableVirtual, - [self.crystal_ROT, self.thz_wp], - self.thz_pol_get, - self.thz_pol_set, - name="thz_polarization", - ) - # self.thz_polarization = AdjustableVirtual( - # [self.crystal_ROT, self.thz_wp], - # self.thz_pol_get, - # self.thz_pol_set, - # name="thz_polarization", - # ) - self._append( - AdjustableVirtual, - [self.delay_thz, self.delay_800_pump], - self.delay_get, - self.delay_set, - name="combined_delay", - ) +namespace.append_obj( + Incoupling, + lazy=True, + name="las_inc", +) - # self.combined_delay = AdjustableVirtual( - # [self.delay_thz, self.delay_800_pump], - # self.delay_get, - # self.delay_set, - # name="combined_delay", - # ) - def thz_pol_set(self, val): - return 1.0 * val, 1.0 / 2 * val +# class THz_in_air(Assembly): +# def __init__(self, name=None): +# super().__init__(name=name) - def thz_pol_get(self, val, val2): - return 1.0 * val2 +# self._append(SmaractRecord, "SARES23:ESB4", name="eos_rot", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB12", name="eos_tilt", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB5", name="crystal_ROT", is_setting=True) +# self._append(SmaractRecord, "SARES23:LIC15", name="ir_1_z", is_setting=True) +# self._append(SmaractRecord, "SARES23:LIC13", name="ir_1_Ry", is_setting=True) +# self._append(SmaractRecord, "SARES23:LIC14", name="ir_1_Rx", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB10", name="ir_2_Rx", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB7", name="ir_2_Ry", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB9", name="para_2_x", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB3", name="thz_mir_x", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB1", name="thz_mir_z", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB8", name="thz_mir_Ry", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB2", name="thz_mir_Rz", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB6", name="focus_z", is_setting=True) +# self._append( +# MotorRecord, +# "SARES20-MF1:MOT_4", +# name="focus_y", +# is_setting=True, +# is_display=True, +# ) +# self._append(SmaractRecord, "SARES23:ESB14", name="focus_x", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB13", name="focus_Rz", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB15", name="focus_Ry", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB11", name="focus_Rx", is_setting=True) +# self._append(SmaractRecord, "SARES23:LIC18", name="thz_wp", is_setting=True) +# self._append( +# SmaractRecord, "SARES23:LIC16", name="delaystage_thz", is_setting=True +# ) +# self._append(DelayTime, self.delaystage_thz, name="delay_thz", is_setting=True) +# self._append( +# MotorRecord, +# "SLAAR21-LMOT-M521:MOTOR_1", +# name="delaystage_800_pump", +# is_setting=True, +# ) +# self._append( +# DelayTime, self.delaystage_800_pump, name="delay_800_pump", is_setting=True +# ) +# self._append( +# AdjustableFS, +# "/photonics/home/gac-bernina/eco/configuration/combined_delta", +# name="combined_delta", +# default_value=0, +# is_setting=True, +# ) +# self.delay_thz = DelayTime(self.delaystage_thz, name="delay_thz") - def delay_set(self, val): - return 1.0 * val + self.combined_delta(), 1.0 * val +# self._append( +# AdjustableVirtual, +# [self.crystal_ROT, self.thz_wp], +# self.thz_pol_get, +# self.thz_pol_set, +# name="thz_polarization", +# ) +# # self.thz_polarization = AdjustableVirtual( +# # [self.crystal_ROT, self.thz_wp], +# # self.thz_pol_get, +# # self.thz_pol_set, +# # name="thz_polarization", +# # ) +# self._append( +# AdjustableVirtual, +# [self.delay_thz, self.delay_800_pump], +# self.delay_get, +# self.delay_set, +# name="combined_delay", +# ) - def delay_get(self, val, val2): - return 1.0 * val2 +# # self.combined_delay = AdjustableVirtual( +# # [self.delay_thz, self.delay_800_pump], +# # self.delay_get, +# # self.delay_set, +# # name="combined_delay", +# # ) + +# def thz_pol_set(self, val): +# return 1.0 * val, 1.0 / 2 * val + +# def thz_pol_get(self, val, val2): +# return 1.0 * val2 + +# def delay_set(self, val): +# return 1.0 * val + self.combined_delta(), 1.0 * val + +# def delay_get(self, val, val2): +# return 1.0 * val2 # namespace.append_obj( @@ -1624,105 +1624,106 @@ from eco.timing.event_timing_new_new import EvrOutput from eco.devices_general.digitizers import DigitizerIoxosBoxcarChannel from eco.elements.adjustable import AdjustableVirtual import numpy as np -class Tapedrive(Assembly): - def __init__(self, name=None): - super().__init__(name=name) - self._append( - AdjustablePv, "KERNVARIABLES:DELAYBETWEENXFELANDLASER", name="delay" - ) - self._append(SmaractRecord, "SARES23:ESB18", name="freespace_pitch") - self._append(SmaractRecord, "SARES23:ESB13", name="freespace_roll") - self._append(MotorRecord, "SARES20-MF1:MOT_7", name="rot_analyzer_hor") - self._append(MotorRecord, "SARES20-MF1:MOT_8", name="rot_analyzer_ver") - self._append(AnalogOutput, "SARES20-CWAG-GPS01:DAC01", name="shutter1") - self._append(AnalogOutput, "SARES20-CWAG-GPS01:DAC02", name="shutter2") - self._append(AnalogOutput, "SARES20-CWAG-GPS01:DAC03", name="shutter3") - self._append(AnalogOutput, "SARES20-CWAG-GPS01:DAC04", name="shutter4") +# class Tapedrive(Assembly): +# def __init__(self, name=None): +# super().__init__(name=name) +# self._append( +# AdjustablePv, "KERNVARIABLES:DELAYBETWEENXFELANDLASER", name="delay" +# ) +# self._append(SmaractRecord, "SARES23:ESB18", name="freespace_pitch") +# self._append(SmaractRecord, "SARES23:ESB13", name="freespace_roll") +# self._append(MotorRecord, "SARES20-MF1:MOT_7", name="rot_analyzer_hor") +# self._append(MotorRecord, "SARES20-MF1:MOT_8", name="rot_analyzer_ver") - self._append( - EvrOutput, - f"SARES20-CVME-01-EVR0:RearUniv0", - pulsers=evr.pulsers, - name=f"trigger_patch1_bnc6", - is_setting=True, - # is_display="recursive", - ) - self._append( - EvrOutput, - f"SARES20-CVME-01-EVR0:RearUniv1", - pulsers=evr.pulsers, - name=f"trigger_patch2_bnc6", - is_setting=True, - # is_display="recursive", - ) +# self._append(AnalogOutput, "SARES20-CWAG-GPS01:DAC01", name="shutter1") +# self._append(AnalogOutput, "SARES20-CWAG-GPS01:DAC02", name="shutter2") +# self._append(AnalogOutput, "SARES20-CWAG-GPS01:DAC03", name="shutter3") +# self._append(AnalogOutput, "SARES20-CWAG-GPS01:DAC04", name="shutter4") - self._append( - Jungfrau, - "JF07T32V01", - config_adj=daq.config_JFs, - pgroup_adj=config_bernina.pgroup, - name="det_diff", - is_setting=True, - is_status=True, - # is_display="recursive", - ) - self._append( - Jungfrau, - "JF05T01V01", - config_adj=daq.config_JFs, - pgroup_adj=config_bernina.pgroup, - name="det_spect", - is_setting=True, - is_status=True, - # is_display="recursive", - ) - self._append( - Jungfrau, - "JF03T01V01", - config_adj=daq.config_JFs, - pgroup_adj=config_bernina.pgroup, - name="det_imon", - is_setting=True, - is_status=True, - # is_display="recursive", - ) +# self._append( +# EvrOutput, +# f"SARES20-CVME-01-EVR0:RearUniv0", +# pulsers=evr.pulsers, +# name=f"trigger_patch1_bnc6", +# is_setting=True, +# # is_display="recursive", +# ) +# self._append( +# EvrOutput, +# f"SARES20-CVME-01-EVR0:RearUniv1", +# pulsers=evr.pulsers, +# name=f"trigger_patch2_bnc6", +# is_setting=True, +# # is_display="recursive", +# ) - self._append( - DigitizerIoxosBoxcarChannel, "SARES20-LSCP9-FNS:CH1", name="diode_1" - ) - self._append( - DigitizerIoxosBoxcarChannel, "SARES20-LSCP9-FNS:CH2", name="diode_2" - ) +# self._append( +# Jungfrau, +# "JF07T32V01", +# config_adj=daq.config_JFs, +# pgroup_adj=config_bernina.pgroup, +# name="det_diff", +# is_setting=True, +# is_status=True, +# # is_display="recursive", +# ) +# self._append( +# Jungfrau, +# "JF05T01V01", +# config_adj=daq.config_JFs, +# pgroup_adj=config_bernina.pgroup, +# name="det_spect", +# is_setting=True, +# is_status=True, +# # is_display="recursive", +# ) +# self._append( +# Jungfrau, +# "JF03T01V01", +# config_adj=daq.config_JFs, +# pgroup_adj=config_bernina.pgroup, +# name="det_imon", +# is_setting=True, +# is_status=True, +# # is_display="recursive", +# ) + +# self._append( +# DigitizerIoxosBoxcarChannel, "SARES20-LSCP9-FNS:CH1", name="diode_1" +# ) +# self._append( +# DigitizerIoxosBoxcarChannel, "SARES20-LSCP9-FNS:CH2", name="diode_2" +# ) - self._append( - AdjustableFS, - "/photonics/home/gac-bernina/eco/configuration/p20231_mono_und_offset", - name="mono_und_calib", - default_value=[[6500,0],[7100,0]], - is_setting=True, - ) +# self._append( +# AdjustableFS, +# "/photonics/home/gac-bernina/eco/configuration/p20231_mono_und_offset", +# name="mono_und_calib", +# default_value=[[6500,0],[7100,0]], +# is_setting=True, +# ) - def en_set(en): - ofs = np.array(self.mono_und_calib()).T - fel_ofs = ofs[1][np.argmin(abs(ofs[0]-en))] - return en , en/1000 - fel_ofs - def en_get(monoen, felen): - return monoen - self._append( - AdjustableVirtual, - [mono, fel.aramis_photon_energy_undulators], - en_get, - en_set, - name="mono_und_energy", - ) - def add_mono_und_calibration(self): - mono_energy = mono.get_current_value() - fel_offset = mono.get_current_value() /1000 - fel.aramis_photon_energy_undulators.get_current_value() - self.mono_und_calib.mvr([[mono_energy,fel_offset]]) +# def en_set(en): +# ofs = np.array(self.mono_und_calib()).T +# fel_ofs = ofs[1][np.argmin(abs(ofs[0]-en))] +# return en , en/1000 - fel_ofs +# def en_get(monoen, felen): +# return monoen +# self._append( +# AdjustableVirtual, +# [mono, fel.aramis_photon_energy_undulators], +# en_get, +# en_set, +# name="mono_und_energy", +# ) +# def add_mono_und_calibration(self): +# mono_energy = mono.get_current_value() +# fel_offset = mono.get_current_value() /1000 - fel.aramis_photon_energy_undulators.get_current_value() +# self.mono_und_calib.mvr([[mono_energy,fel_offset]]) -namespace.append_obj(Tapedrive, name="tapedrive", lazy=True) +# namespace.append_obj(Tapedrive, name="tapedrive", lazy=True) #### pgroup specific appending, might be temporary at this location #### diff --git a/eco/bernina/config.py b/eco/bernina/config.py index 742e55b..a4884d0 100755 --- a/eco/bernina/config.py +++ b/eco/bernina/config.py @@ -234,7 +234,7 @@ components = [ # "kwargs": {"VME_crate": "SAROP21-CVME-PBPS1", "link": 9}, # }, { - "name": "mon_opt", + "name": "mon_opt_old", "z_und": 133, "desc": "Intensity/position monitor after Optics hutch", "type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS_new", diff --git a/eco/endstations/bernina_sample_environments.py b/eco/endstations/bernina_sample_environments.py index 3e8f0c4..14ca0d8 100644 --- a/eco/endstations/bernina_sample_environments.py +++ b/eco/endstations/bernina_sample_environments.py @@ -9,7 +9,6 @@ from epics import PV from ..aliases import Alias, append_object_to_object from time import sleep import escape.parse.swissfel as sf -from ..bernina import config import pylab as plt import escape from pathlib import Path diff --git a/eco/xdiagnostics/intensity_monitors.py b/eco/xdiagnostics/intensity_monitors.py index 7af01a5..0f505f3 100755 --- a/eco/xdiagnostics/intensity_monitors.py +++ b/eco/xdiagnostics/intensity_monitors.py @@ -146,12 +146,16 @@ class SolidTargetDetectorPBPS(Assembly): # VME_crate=None, # pipeline=None, # link=None, + channel_xpos=None, + channel_ypos=None, + channel_intensity=None, diode_channels_raw={}, # ch_up=12, # ch_down=13, # ch_left=15, # ch_right=14, # elog=None, + use_calibration=True, name=None, # calc=None, # calc_calib={}, @@ -170,19 +174,37 @@ class SolidTargetDetectorPBPS(Assembly): self._append( AdjustablePvEnum, pvname + ":PROBE_SP", name="target", is_setting=True ) + if channel_intensity: + self._append( + DetectorPvDataStream, + channel_intensity, + name="intensity", + is_setting=False, + ) + else: + self._append( + DetectorPvDataStream, + pvname + ":INTENSITY", + name="intensity", + is_setting=False, + ) - self._append( - DetectorPvDataStream, - pvname + ":INTENSITY", - name="intensity", - is_setting=False, - ) - self._append( - DetectorPvDataStream, pvname + ":XPOS", name="xpos", is_setting=False - ) - self._append( - DetectorPvDataStream, pvname + ":YPOS", name="ypos", is_setting=False - ) + if channel_xpos: + self._append( + DetectorPvDataStream, channel_xpos, name="xpos", is_setting=False + ) + else: + self._append( + DetectorPvDataStream, pvname + ":XPOS", name="xpos", is_setting=False + ) + if channel_ypos: + self._append( + DetectorPvDataStream, channel_ypos, name="ypos", is_setting=False + ) + else: + self._append( + DetectorPvDataStream, pvname + ":YPOS", name="ypos", is_setting=False + ) if diode_channels_raw: self._append( @@ -210,30 +232,31 @@ class SolidTargetDetectorPBPS(Assembly): is_setting=False, ) - # Calibration calculation record + if use_calibration: + # Calibration calculation record - # Calibration - self._append( - CalibrationRecord, - pvname + ":INTENSITY", - name="calib_intensity", - is_setting=True, - is_display=False, - ) - self._append( - CalibrationRecord, - pvname + ":XPOS", - name="calib_xpos", - is_setting=True, - is_display=False, - ) - self._append( - CalibrationRecord, - pvname + ":YPOS", - name="calib_ypos", - is_setting=True, - is_display=False, - ) + # Calibration + self._append( + CalibrationRecord, + pvname + ":INTENSITY", + name="calib_intensity", + is_setting=True, + is_display=False, + ) + self._append( + CalibrationRecord, + pvname + ":XPOS", + name="calib_xpos", + is_setting=True, + is_display=False, + ) + self._append( + CalibrationRecord, + pvname + ":YPOS", + name="calib_ypos", + is_setting=True, + is_display=False, + ) def get_calibration_values(self, seconds=5): self.x_diodes.set_target_value(0).wait() From c791359a56ba9d2df5d4a9ad994027088447b646 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Wed, 12 Oct 2022 17:03:45 +0200 Subject: [PATCH 22/52] adjusts --- eco/bernina/bernina.py | 16 +++- eco/detector/detectors_psi.py | 104 +++++++++++++++++++++++++ eco/timing/event_timing_new_new.py | 6 +- eco/xdiagnostics/intensity_monitors.py | 91 +++++++++++++--------- 4 files changed, 180 insertions(+), 37 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index fd36318..c4bc6b5 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -294,6 +294,11 @@ namespace.append_obj( "left": "SLAAR21-LSCP1-FNS:CH4:VAL_GET", "right": "SLAAR21-LSCP1-FNS:CH5:VAL_GET", }, + calibration_records={ + "intensity": "SLAAR21-LTIM01-EVR0:CALCI", + "xpos": "SLAAR21-LTIM01-EVR0:CALCX", + "ypos": "SLAAR21-LTIM01-EVR0:CALCY", + }, name="mon_opt", module_name="eco.xdiagnostics.intensity_monitors", lazy=True, @@ -404,10 +409,19 @@ namespace.append_obj( "SIN-TIMAST-TMA", name="event_master", module_name="eco.timing.event_timing_new_new", + # pv_eventset="SAR-CVME-TIFALL5:EvtSet", # lazy=False, lazy=True, ) -# namespace.append_obj("TimingSystem",pv_master="SIN-TIMAST-TMA",pv_pulse_id="SARES20-CVME-01-EVR0:RX-PULSEID",name='event_system',module_name = "eco.timing.event_timing_new_new",lazy=True) +namespace.append_obj( + "TimingSystem", + pv_master="SIN-TIMAST-TMA", + pv_pulse_id="SARES20-CVME-01-EVR0:RX-PULSEID", + pv_eventset="SAR-CVME-TIFALL5:EvtSet", + name="event_system", + module_name="eco.timing.event_timing_new_new", + lazy=True, +) # namespace.append_obj('Daq', instrument= "bernina",pgroup= config_berninamesp["pgroup"], channels_JF=channels_JF, channels_BS=channels_BS,channels_BSCAM=channels_BSCAM,channels_CA=channels_CA,pulse_id_adj="SLAAR21-LTIM01-EVR0:RX-PULSEID",event_master=event_system.event_master,detectors_event_code=50,name='daq',module_name='eco.acquisition.daq_client') diff --git a/eco/detector/detectors_psi.py b/eco/detector/detectors_psi.py index 3628b6b..5acdf7e 100644 --- a/eco/detector/detectors_psi.py +++ b/eco/detector/detectors_psi.py @@ -6,6 +6,7 @@ from bsread.bsavail import pollStream from bsread import dispatcher, source from ..epics import get_from_archive from escape import stream +from time import time, sleep @get_from_archive @@ -40,6 +41,109 @@ class DetectorBsStream: while not done: done = foo(s.receive()) + def collect(self, seconds=None, samples=None): + if (not seconds) and (not samples): + raise Exception( + "Either a time interval or number of samples need to be defined." + ) + try: + self._pv.callbacks.pop(self._collection["ix_cb"]) + except: + pass + self._collection = {"done": False} + self.data_collected = [] + if seconds: + self._collection["start_time"] = time() + self._collection["seconds"] = seconds + stopcond = ( + lambda: (time() - self._collection["start_time"]) + > self._collection["seconds"] + ) + + def addData(**kw): + if not stopcond(): + self.data_collected.append(kw["value"]) + else: + self._pv.callbacks.pop(self._collection["ix_cb"]) + self._collection["done"] = True + + elif samples: + self._collection["samples"] = samples + stopcond = lambda: len(self.data_collected) >= self._collection["samples"] + + def addData(**kw): + self.data_collected.append(kw["value"]) + if stopcond(): + self._pv.callbacks.pop(self._collection["ix_cb"]) + self._collection["done"] = True + + self._collection["ix_cb"] = self._pv.add_callback(addData) + time_wait_start = time() + while not self._collection["done"]: + sleep(0.005) + if seconds: + if (time() - time_wait_start) > seconds: + if len(self.data_collected) == 0: + print( + f"No {self.name}({self.Id}) data update in time interval, reporting last value" + ) + self._pv.callbacks.pop(self._collection["ix_cb"]) + self.data_collected.append(self.get_current_value()) + break + + return self.data_collected + + def acquire(self, hold=False, seconds=None, samples=None, **kwargs): + return Acquisition( + acquire=lambda: self.collect(seconds=seconds, samples=samples, **kwargs), + hold=hold, + stopper=None, + get_result=lambda: self.data_collected, + ) + + def accumulate_ring_buffer(self, n_buffer): + if not hasattr(self, "_accumulate"): + self._accumulate = {"n_buffer": n_buffer, "ix": 0, "n_cb": -1} + else: + self._accumulate["n_buffer"] = n_buffer + self._accumulate["ix"] = 0 + self._pv.callbacks.pop(self._accumulate["n_cb"], None) + self._data = np.squeeze(np.zeros([n_buffer * 2, self._pv.count])) * np.nan + + def addData(**kw): + self._accumulate["ix"] = (self._accumulate["ix"] + 1) % self._accumulate[ + "n_buffer" + ] + self._data[self._accumulate["ix"] :: self._accumulate["n_buffer"]] = kw[ + "value" + ] + + self._accumulate["n_cb"] = self._pv.add_callback(addData) + + def accumulate_start(self): + if not hasattr(self, "_accumulate_inf"): + self._accumulate_inf = {"n_cb": -1} + self._pv.callbacks.pop(self._accumulate_inf["n_cb"], None) + self._data_inf = [] + + def addData(**kw): + self._data_inf.append(kw["value"]) + + self._accumulate_inf["n_cb"] = self._pv.add_callback(addData) + + def accumulate_stop(self): + self._pv.callbacks.pop(self._accumulate_inf["n_cb"], None) + return self._data_inf + + @property + def data(self): + return self._data[ + self._accumulate["ix"] + + 1 : self._accumulate["ix"] + + 1 + + self._accumulate["n_buffer"] + ] + @get_from_archive class DetectorBsCam: diff --git a/eco/timing/event_timing_new_new.py b/eco/timing/event_timing_new_new.py index 633cb35..2508933 100644 --- a/eco/timing/event_timing_new_new.py +++ b/eco/timing/event_timing_new_new.py @@ -2,6 +2,7 @@ from epics import caget_many from ..elements.adjustable import AdjustableMemory, AdjustableVirtual from ..epics.adjustable import AdjustablePv, AdjustablePvEnum, AdjustablePvString from ..epics.detector import DetectorPvData, DetectorPvDataStream +from ..detector.detectors_psi import DetectorBsStream from eco.epics.utilities_epics import EpicsString import logging from ..elements.assembly import Assembly @@ -13,13 +14,16 @@ logging.getLogger("cta_lib").setLevel(logging.WARNING) class TimingSystem(Assembly): """This is a wrapper object for the global timing system at SwissFEL""" - def __init__(self, pv_master=None, pv_pulse_id=None, name=None): + def __init__(self, pv_master=None, pv_pulse_id=None, pv_eventset=None, name=None): super().__init__(name=name) self._append( MasterEventSystem, pv_master, name="event_master", is_display="recursive" ) self._append(DetectorPvDataStream, pv_pulse_id, name="pulse_id") + if pv_eventset: + self._append(DetectorBsStream, pv_eventset, name="eventset") + # EVR output mapping evr_mapping = { diff --git a/eco/xdiagnostics/intensity_monitors.py b/eco/xdiagnostics/intensity_monitors.py index 0f505f3..2c515df 100755 --- a/eco/xdiagnostics/intensity_monitors.py +++ b/eco/xdiagnostics/intensity_monitors.py @@ -156,6 +156,7 @@ class SolidTargetDetectorPBPS(Assembly): # ch_right=14, # elog=None, use_calibration=True, + calibration_records=None, name=None, # calc=None, # calc_calib={}, @@ -176,57 +177,53 @@ class SolidTargetDetectorPBPS(Assembly): ) if channel_intensity: self._append( - DetectorPvDataStream, + DetectorBsStream, channel_intensity, name="intensity", is_setting=False, ) else: self._append( - DetectorPvDataStream, + DetectorBsStream, pvname + ":INTENSITY", name="intensity", is_setting=False, ) if channel_xpos: - self._append( - DetectorPvDataStream, channel_xpos, name="xpos", is_setting=False - ) + self._append(DetectorBsStream, channel_xpos, name="xpos", is_setting=False) else: self._append( - DetectorPvDataStream, pvname + ":XPOS", name="xpos", is_setting=False + DetectorBsStream, pvname + ":XPOS", name="xpos", is_setting=False ) if channel_ypos: - self._append( - DetectorPvDataStream, channel_ypos, name="ypos", is_setting=False - ) + self._append(DetectorBsStream, channel_ypos, name="ypos", is_setting=False) else: self._append( - DetectorPvDataStream, pvname + ":YPOS", name="ypos", is_setting=False + DetectorBsStream, pvname + ":YPOS", name="ypos", is_setting=False ) if diode_channels_raw: self._append( - DetectorPvDataStream, + DetectorBsStream, diode_channels_raw["up"], name="signal_up_raw", is_setting=False, ) self._append( - DetectorPvDataStream, + DetectorBsStream, diode_channels_raw["down"], name="signal_down_raw", is_setting=False, ) self._append( - DetectorPvDataStream, + DetectorBsStream, diode_channels_raw["left"], name="signal_left_raw", is_setting=False, ) self._append( - DetectorPvDataStream, + DetectorBsStream, diode_channels_raw["right"], name="signal_right_raw", is_setting=False, @@ -236,27 +233,51 @@ class SolidTargetDetectorPBPS(Assembly): # Calibration calculation record # Calibration - self._append( - CalibrationRecord, - pvname + ":INTENSITY", - name="calib_intensity", - is_setting=True, - is_display=False, - ) - self._append( - CalibrationRecord, - pvname + ":XPOS", - name="calib_xpos", - is_setting=True, - is_display=False, - ) - self._append( - CalibrationRecord, - pvname + ":YPOS", - name="calib_ypos", - is_setting=True, - is_display=False, - ) + if calibration_records: + self._append( + CalibrationRecord, + calibration_records["intensity"], + name="calib_intensity", + is_setting=True, + is_display=False, + ) + self._append( + CalibrationRecord, + calibration_records["xpos"], + name="calib_xpos", + is_setting=True, + is_display=False, + ) + self._append( + CalibrationRecord, + calibration_records["ypos"], + name="calib_ypos", + is_setting=True, + is_display=False, + ) + + else: + self._append( + CalibrationRecord, + pvname + ":INTENSITY", + name="calib_intensity", + is_setting=True, + is_display=False, + ) + self._append( + CalibrationRecord, + pvname + ":XPOS", + name="calib_xpos", + is_setting=True, + is_display=False, + ) + self._append( + CalibrationRecord, + pvname + ":YPOS", + name="calib_ypos", + is_setting=True, + is_display=False, + ) def get_calibration_values(self, seconds=5): self.x_diodes.set_target_value(0).wait() From ec2d588c117edd379a90d7cd4a7c1c287919673d Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Mon, 28 Nov 2022 22:43:16 +0100 Subject: [PATCH 23/52] fixes --- eco/acquisition/scan.py | 14 + eco/bernina/bernina.py | 65 +++- eco/detector/detectors_psi.py | 4 + eco/devices_general/motors.py | 7 + eco/elements/detector.py | 1 + .../bernina_sample_environments.py | 70 +++-- eco/epics/adjustable.py | 10 +- eco/loptics/bernina_laser.py | 93 ++++-- eco/timing/event_timing_new_new.py | 8 +- eco/timing/lasertiming_edwin.py | 103 ++++-- eco/timing/palm.py | 24 -- eco/timing/psen.py | 24 -- eco/timing/sequencer.py | 176 ----------- eco/timing/timing_diag.py | 2 +- eco/utilities/recspace.py | 42 ++- eco/xdiagnostics/intensity_monitors.py | 296 +++++++++++++++++- eco/xdiagnostics/profile_monitors.py | 19 +- eco/xdiagnostics/timetools.py | 61 ++-- 18 files changed, 628 insertions(+), 391 deletions(-) delete mode 100755 eco/timing/palm.py delete mode 100755 eco/timing/psen.py delete mode 100644 eco/timing/sequencer.py diff --git a/eco/acquisition/scan.py b/eco/acquisition/scan.py index a702a52..230ba17 100755 --- a/eco/acquisition/scan.py +++ b/eco/acquisition/scan.py @@ -51,6 +51,7 @@ class Scan: Npulses=100, basepath="", scan_info_dir="", + settling_time=0, checker=None, scan_directories=False, callbackStartStep=None, @@ -78,6 +79,7 @@ class Scan: self.pulses_done = [] self.readbacks = [] self.counterCallers = counterCallers + self.settling_time = settling_time self.fina = fina self.nextStep = 0 self.basepath = basepath @@ -157,6 +159,10 @@ class Scan: ms.append(adj.set_target_value(tv)) for tm in ms: tm.wait() + + # settling + sleep(self.settling_time) + readbacks_step = [] adjs_name = [] adjs_offset = [] @@ -376,6 +382,7 @@ class Scans: file_name="", counters=[], start_immediately=True, + settling_time=0, step_info=None, return_at_end=True, ): @@ -396,6 +403,7 @@ class Scans: Npulses=N_pulses, basepath=self.data_base_dir, scan_info_dir=self.scan_info_dir, + settling_time=settling_time, checker=self.checker, scan_directories=self._scan_directories, callbacks_start_scan=self.callbacks_start_scan, @@ -421,6 +429,7 @@ class Scans: start_immediately=True, step_info=None, return_at_end="question", + settling_time=0, ): positions = np.linspace(start_pos, end_pos, N_intervals + 1) values = [[tp] for tp in positions] @@ -437,6 +446,7 @@ class Scans: basepath=self.data_base_dir, scan_info_dir=self.scan_info_dir, checker=self.checker, + settling_time=settling_time, scan_directories=self._scan_directories, return_at_end=return_at_end, callbacks_start_scan=self.callbacks_start_scan, @@ -459,6 +469,7 @@ class Scans: file_name="", counters=[], start_immediately=True, + settling_time=0, step_info=None, return_at_end="question", ): @@ -480,6 +491,7 @@ class Scans: checker=self.checker, scan_directories=self._scan_directories, return_at_end=return_at_end, + settling_time=settling_time, callbacks_start_scan=self.callbacks_start_scan, callbacks_end_scan=self.callbacks_end_scan, run_table=self._run_table, @@ -504,6 +516,7 @@ class Scans: file_name=None, counters=[], start_immediately=True, + settling_time=0, step_info=None, return_at_end="question", ): @@ -523,6 +536,7 @@ class Scans: scan_info_dir=self.scan_info_dir, checker=self.checker, scan_directories=self._scan_directories, + settling_time=settling_time, return_at_end=return_at_end, callbacks_start_scan=self.callbacks_start_scan, callbacks_end_scan=self.callbacks_end_scan, diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index c4bc6b5..0aaf6e4 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -141,6 +141,12 @@ namespace.append_obj( "left": "SAROP21-CVME-PBPS1:Lnk9Ch2-DATA-SUM", "right": "SAROP21-CVME-PBPS1:Lnk9Ch1-DATA-SUM", }, + fe_digi_channels={ + "left": "SAROP21-CVME-PBPS1:Lnk9Ch2", + "right": "SAROP21-CVME-PBPS1:Lnk9Ch1", + "up": "SAROP21-CVME-PBPS1:Lnk9Ch3", + "down": "SAROP21-CVME-PBPS1:Lnk9Ch4", + }, name="mon_mono", module_name="eco.xdiagnostics.intensity_monitors", lazy=True, @@ -282,6 +288,21 @@ namespace.append_obj( name="reflaser", lazy=True, ) +namespace.append_obj( + "SpectralEncoder", + "SAROP21-PSEN135", + module_name="eco.xdiagnostics.timetools", + name="tt_opt", + mirror_stages={ + "las_in_rx": "SLAAR21-LMOT-M538:MOT", + "las_in_ry": "SLAAR21-LMOT-M537:MOT", + "las_out_rx": "SLAAR21-LMOT-M536:MOT", + "las_out_ry": "SLAAR21-LMOT-M535:MOT", + }, + lazy=True, +) + + namespace.append_obj( "SolidTargetDetectorPBPS", "SAROP21-PBPS133", @@ -366,6 +387,21 @@ namespace.append_obj( lazy=True, ) +namespace.append_obj( + "SolidTargetDetectorBerninaUSD", + "SARES23:LIC12", + # diode_channels_raw={ + # "up": "", + # "down": "", + # "left": "", + # "right":"", + # }, + module_name="eco.xdiagnostics.intensity_monitors", + name="mon_kb", + lazy=True, +) + + namespace.append_obj( "DownstreamDiagnostic", name="dsd", @@ -657,7 +693,7 @@ namespace.append_obj( module_name="eco.xoptics.kb_bernina", usd_table=usd_table, name="kb", - diffractometer=xrd, + diffractometer=gps, lazy=True, ) @@ -1149,12 +1185,20 @@ namespace.append_obj( namespace.append_obj( "CameraBasler", - "SARES20-CAMS142-C2", + "SARES20-CAMS142-M2", lazy=True, name="samplecam_sideview", module_name="eco.devices_general.cameras_swissfel", ) +namespace.append_obj( + "CameraBasler", + "SARES20-CAMS142-C2", + lazy=True, + name="samplecam_sideview_45deg", + module_name="eco.devices_general.cameras_swissfel", +) + # namespace.append_obj( # "CameraBasler", # "SARES20-CAMS142-C3", @@ -1269,12 +1313,6 @@ class N2jet(Assembly): ) -namespace.append_obj( - N2jet, - lazy=True, - name="jet", -) - # ad hoc incoupling device class Incoupling(Assembly): def __init__(self, name=None): @@ -1286,10 +1324,17 @@ class Incoupling(Assembly): # self._append(SmaractRecord, "SARES23:ESB17", name="rotation", is_setting=True) +# namespace.append_obj( +# Incoupling, +# lazy=True, +# name="las_inc", +# ) + namespace.append_obj( - Incoupling, + "High_field_thz_chamber", + name="thc", lazy=True, - name="las_inc", + module_name="eco.endstations.bernina_sample_environments", ) diff --git a/eco/detector/detectors_psi.py b/eco/detector/detectors_psi.py index 5acdf7e..742e1f6 100644 --- a/eco/detector/detectors_psi.py +++ b/eco/detector/detectors_psi.py @@ -7,6 +7,7 @@ from bsread import dispatcher, source from ..epics import get_from_archive from escape import stream from time import time, sleep +from eco.acquisition.utilities import Acquisition @get_from_archive @@ -25,7 +26,10 @@ class DetectorBsStream: self.stream = stream.EscData(source=stream.EventSource(self.bs_channel, None)) def get_current_value(self, force_bsstream=False): + if not force_bsstream: + if not hasattr(self, "_pv"): + return None return self._pv.get() else: raise NotImplementedError( diff --git a/eco/devices_general/motors.py b/eco/devices_general/motors.py index 38cb1fc..b5b809f 100755 --- a/eco/devices_general/motors.py +++ b/eco/devices_general/motors.py @@ -601,8 +601,15 @@ class MotorRecord(Assembly): """Adjustable convention""" def changer(value): + statflag_start = self.status_flag.get_current_value() + if not statflag_start.value == 0: + raise AdjustableError(f'Motor {self.alias.get_full_name()}({self.pvname}) cannot start moving with status flag {statflag_start.name} .') self._status = self._motor.move(value, ignore_limits=(not check), wait=True) self._status_message = _status_messages[self._status] + statflag_end = self.status_flag.get_current_value() + if not statflag_end.value == 0: + raise AdjustableError(f'Motor {self.alias.get_full_name()}({self.pvname}) cannot finish move with status flag {statflag_end.name} .') + if self._status < 0: raise AdjustableError(self._status_message) elif self._status > 0: diff --git a/eco/elements/detector.py b/eco/elements/detector.py index c5054a9..41d5ef2 100644 --- a/eco/elements/detector.py +++ b/eco/elements/detector.py @@ -1,3 +1,4 @@ +from eco.elements.adjustable import AdjustableMemory from eco.elements.assembly import Assembly from eco.aliases import Alias diff --git a/eco/endstations/bernina_sample_environments.py b/eco/endstations/bernina_sample_environments.py index 14ca0d8..00f2bd1 100644 --- a/eco/endstations/bernina_sample_environments.py +++ b/eco/endstations/bernina_sample_environments.py @@ -1,8 +1,7 @@ import sys sys.path.append("..") -from ..devices_general.motors import MotorRecord, SmaractStreamdevice -from ..devices_general.smaract import SmarActRecord +from ..devices_general.motors import MotorRecord, SmaractRecord from ..epics.adjustable import AdjustablePv import numpy as np from epics import PV @@ -32,20 +31,19 @@ def addMotorRecordToSelf(self, name=None, Id=None): def addSmarActRecordToSelf(self, Id=None, name=None, **kwargs): - self.__dict__[name] = SmaractStreamdevice(Id, name=name, **kwargs) + self.__dict__[name] = SmaractRecord(Id, name=name, **kwargs) self.alias.append(self.__dict__[name].alias) class High_field_thz_chamber(Assembly): - def __init__(self, name=None, Id=None, alias_namespace=None, configuration=[]): + def __init__(self, name=None, alias_namespace=None, configuration=[]): super().__init__(name=name) - self.Id = Id self.name = name self.alias = Alias(name) self.par_out_pos = [35, -9.5] self.motor_configuration = { "rx": { - "id": "-ESB13", + "id": "SARES23:ESB13", "pv_descr": "Motor7:1 THz Chamber Rx", "type": 2, "sensor": 1, @@ -54,7 +52,7 @@ class High_field_thz_chamber(Assembly): "kwargs": {"accuracy": 0.01}, }, "x": { - "id": "-ESB14", + "id": "SARES23:ESB14", "pv_descr": "Motor7:2 THz Chamber x ", "type": 1, "sensor": 0, @@ -62,7 +60,7 @@ class High_field_thz_chamber(Assembly): "home_direction": "back", }, "z": { - "id": "-ESB10", + "id": "SARES23:ESB10", "pv_descr": "Motor6:1 THz Chamber z ", "type": 1, "sensor": 0, @@ -70,7 +68,7 @@ class High_field_thz_chamber(Assembly): "home_direction": "back", }, "ry": { - "id": "-ESB11", + "id": "SARES23:ESB11", "pv_descr": "Motor6:2 THz Chamber Ry", "type": 2, "sensor": 1, @@ -78,7 +76,7 @@ class High_field_thz_chamber(Assembly): "home_direction": "back", }, "rz": { - "id": "-ESB12", + "id": "SARES23:ESB12", "pv_descr": "Motor6:3 THz Chamber Rz", "type": 2, "sensor": 1, @@ -90,33 +88,41 @@ class High_field_thz_chamber(Assembly): ### lakeshore temperatures #### self._append( AdjustablePv, - pvsetname="SARES20-CRYO:TEMP.VAL", - pvreadbackname="SARES20-CRYO:TEMP_RBV", + pvsetname="SARES20-LS336:LOOP1_SP", + pvreadbackname="SARES20-LS336:A_RBV", accuracy=0.1, name="temp_sample", is_setting=False, ) self._append( AdjustablePv, - pvsetname="SARES20-CRYO:TEMP-B", - pvreadbackname="SARES20-CRYO:TEMP-B_RBV", + pvsetname="SARES20-LS336:LOOP2_SP", + pvreadbackname="SARES20-LS336:B_RBV", accuracy=0.1, name="temp_coldfinger", is_setting=False, ) + ### in vacuum smaract motors ### + #for name, config in self.motor_configuration.items(): + # if "kwargs" in config.keys(): + # tmp_kwargs = config["kwargs"] + # else: + # tmp_kwargs = {} + # self._append( + # SmaractStreamdevice, + # pvname=Id + config["id"], + # name=name, + # is_setting=True, + # **tmp_kwargs, + # ) ### in vacuum smaract motors ### for name, config in self.motor_configuration.items(): - if "kwargs" in config.keys(): - tmp_kwargs = config["kwargs"] - else: - tmp_kwargs = {} self._append( - SmaractStreamdevice, - pvname=Id + config["id"], + SmaractRecord, + pvname=config["id"], name=name, is_setting=True, - **tmp_kwargs, ) self._append( AdjustableFS, @@ -186,12 +192,12 @@ class High_field_thz_chamber(Assembly): def set_stage_config(self): for name, config in self.motor_configuration.items(): mot = self.__dict__[name] - mot.caqtdm_name(config["pv_descr"]) - mot.stage_type(config["type"]) + mot.description(config["pv_descr"]) + #mot.stage_type(config["type"]) mot.sensor_type(config["sensor"]) - mot.speed(config["speed"]) + mot.max_frequency(config["speed"]) sleep(0.5) - mot.calibrate_sensor(1) + mot.calibrate_sensor() def home_smaract_stages(self, stages=None): if stages == None: @@ -208,25 +214,27 @@ class High_field_thz_chamber(Assembly): ) sleep(1) if config["home_direction"] == "back": - mot.home_backward(1) - while mot.status_channel().value == 7: + mot.home_reverse(1) + sleep(.5) + while not mot.flags.motion_complete(): sleep(1) - if mot.is_homed() == 0: + if not mot.flags.is_homed(): print( "Homing failed, try homing {} in forward direction".format(name) ) mot.home_forward(1) elif config["home_direction"] == "forward": mot.home_forward(1) - while mot.status_channel().value == 7: + sleep(.5) + while not mot.flags.motion_complete(): sleep(1) - if mot.is_homed() == 0: + if not mot.flags.is_homed(): print( "Homing failed, try homing {} in backward direction".format( name ) ) - mot.home_backward(1) + mot.home_reverse(1) def calc_otti( self, otti_nu=None, otti_del=None, otti_det=None, plotit=True, **kwargs diff --git a/eco/epics/adjustable.py b/eco/epics/adjustable.py index 7542691..ecc7687 100644 --- a/eco/epics/adjustable.py +++ b/eco/epics/adjustable.py @@ -5,7 +5,12 @@ import numpy as np from epics import PV from eco.aliases import Alias -from eco.elements.adjustable import tweak_option, spec_convenience, value_property +from eco.elements.adjustable import ( + AdjustableMemory, + tweak_option, + spec_convenience, + value_property, +) from . import get_from_archive from eco.devices_general.utilities import Changer from ..elements.assembly import Assembly @@ -24,6 +29,7 @@ class AdjustablePv: name=None, elog=None, element_count=None, + unit=None, ): # alias_fields={"setpv": pvsetname, "readback": pvreadbackname}, @@ -38,6 +44,8 @@ class AdjustablePv: self._pv = PV(self.Id, connection_timeout=0.05, count=element_count) self._currentChange = None self.accuracy = accuracy + if unit: + self.unit = AdjustableMemory(unit, name="unit") if pvreadbackname is None: self._pvreadback = PV(self.Id, count=element_count, connection_timeout=0.05) diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index 4e9e653..910acea 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -25,6 +25,18 @@ class IncouplingCleanBernina(Assembly): self._append(SmaractStreamdevice, "SARES23-LIC15", name="transl_vertical") self._append(MotorRecord, "SARES20-MF2:MOT_5", name="transl_horizontal") + +class Spectrometer(Assembly): + def __init__(self, pvname, name=None): + super().__init__(name=name) + self.pvname = pvname + self._append(self, AdjustablePvEnum, pvname + ":TRIGGER", name="trigger_mode") + self._append(self, AdjustablePvEnum, pvname + ":INIT", name="state") + self._append(self, AdjustablePv, pvname + ":EXPOSURE", name="exposure_time") + self._append(self, AdjustablePv, pvname + ":EXPOSURE", name="exposure_time") + self._append(self, DetectorPvData, pvname + ":CENTRE", name="center") + + flag_names_filter_wheel = [ "error", "proc_tongle", @@ -58,9 +70,9 @@ class FilterWheel(Assembly): def __init__(self, pvname, name=None): super().__init__(name=name) self.pvname = pvname - self._append(AdjustablePvEnum, f"{pvname}.VAL", name = "_val", is_setting=True) - self._append(AdjustablePvEnum, f"{pvname}.RBV", name = "_rb", is_setting=True) - self._append(AdjustablePv, f"{pvname}.CMD", name = "_cmd", is_setting=False) + self._append(AdjustablePvEnum, f"{pvname}.VAL", name="_val", is_setting=True) + self._append(AdjustablePvEnum, f"{pvname}.RBV", name="_rb", is_setting=True) + self._append(AdjustablePv, f"{pvname}.CMD", name="_cmd", is_setting=False) self.set_remote_operation() self._append( DetectorPvData, @@ -87,26 +99,24 @@ class FilterWheel(Assembly): def home(self): self.set_remote_operation() self._val(6) - + def is_moving(self): - pass - - + pass class FilterWheelAttenuator(Assembly): def __init__(self, pvname, name=None): super().__init__(name=name) - self._append(FilterWheel, pvname = pvname + "IFW_A", name="wheel_1") - self._append(FilterWheel, pvname = pvname + "IFW_B", name="wheel_2") + self._append(FilterWheel, pvname=pvname + "IFW_A", name="wheel_1") + self._append(FilterWheel, pvname=pvname + "IFW_B", name="wheel_2") self.targets_1 = { - "t": 10**-np.array([0.2, 0.3, 0.5, 0.6, 1.0]), - "pos": np.array([1,2,3,4,5]), + "t": 10 ** -np.array([0.2, 0.3, 0.5, 0.6, 1.0]), + "pos": np.array([1, 2, 3, 4, 5]), } self.targets_2 = { - "t":10**-np.array([0.2, 0.3, 0.4, 0.5, 0.6]), - "pos": np.array([1,2,3,4,5]), + "t": 10 ** -np.array([0.2, 0.3, 0.4, 0.5, 0.6]), + "pos": np.array([1, 2, 3, 4, 5]), } self._calc_transmission() @@ -126,6 +136,7 @@ class FilterWheelAttenuator(Assembly): self.wheel_1.home() self.wheel_2.home() + class LaserBernina(Assembly): def __init__(self, pvname, name=None): super().__init__(name=name) @@ -168,21 +179,24 @@ class LaserBernina(Assembly): ) def wp2uJ(wp): - return np.interp(wp, *np.asarray(self.wp_att_calibration()).T) + try: + return np.interp(wp, *np.asarray(self.wp_att_calibration()).T) + except: + return np.nan self._append( AdjustableVirtual, [self.wp_att], wp2uJ, uJ2wp, name="pulse_energy_pump" ) - #self._append( + # self._append( # MotorRecord, # self.pvname + "-M522:MOTOR_1", # name="delaystage_pump", # is_setting=True, - #) - #self._append( + # ) + # self._append( # DelayTime, self.delaystage_pump, name="delay_pump", is_setting=True - #) + # ) self._append(XltEpics, name="xlt", is_setting=True, is_display="recursive") # Upstairs, Laser 1 LAM self._append( @@ -203,12 +217,8 @@ class LaserBernina(Assembly): # name="delaystage_thz", # is_setting=True, # ) - self._append( - SmaractRecord, "SARES23:ESB3", name="pump_hor", is_setting=True - ) - self._append( - SmaractRecord, "SARES23:ESB18", name="pump_ver", is_setting=True - ) + self._append(SmaractRecord, "SARES23:ESB3", name="pump_hor", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB18", name="pump_ver", is_setting=True) class DelayTime(AdjustableVirtual): @@ -294,13 +304,36 @@ class DelayCompensation(AdjustableVirtual): return s - class PositionMonitors(Assembly): - def __init__(self,name=None): + def __init__(self, name=None): super().__init__(name=name) - self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C551', name='post_compressor_focus', is_display='recursive', is_status=True) - self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C552', name='post_compressor_position', is_display='recursive', is_status=True) - self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C531', name='opaout_position', is_display='recursive', is_status=True) - self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C511', name='opaout_focus', is_display='recursive', is_status=True) + self._append( + CameraPositionMonitor, + "SLAAR21-LCAM-C551", + name="post_compressor_focus", + is_display="recursive", + is_status=True, + ) + self._append( + CameraPositionMonitor, + "SLAAR21-LCAM-C552", + name="post_compressor_position", + is_display="recursive", + is_status=True, + ) + self._append( + CameraPositionMonitor, + "SLAAR21-LCAM-C531", + name="opaout_position", + is_display="recursive", + is_status=True, + ) + self._append( + CameraPositionMonitor, + "SLAAR21-LCAM-C511", + name="opaout_focus", + is_display="recursive", + is_status=True, + ) # self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C541', name='cam541') # self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C542', name='cam542') diff --git a/eco/timing/event_timing_new_new.py b/eco/timing/event_timing_new_new.py index 2508933..55778a5 100644 --- a/eco/timing/event_timing_new_new.py +++ b/eco/timing/event_timing_new_new.py @@ -16,13 +16,15 @@ class TimingSystem(Assembly): def __init__(self, pv_master=None, pv_pulse_id=None, pv_eventset=None, name=None): super().__init__(name=name) + self._append(MasterEventSystem, pv_master, name="event_master", is_display=True) + # self._append(DetectorPvDataStream, pv_pulse_id, name="pulse_id") self._append( - MasterEventSystem, pv_master, name="event_master", is_display="recursive" + DetectorBsStream, "pulse_id", cachannel=pv_pulse_id, name="pulse_id" ) - self._append(DetectorPvDataStream, pv_pulse_id, name="pulse_id") + self._append(DetectorBsStream, "lab_time", cachannel=None, name="lab_time") if pv_eventset: - self._append(DetectorBsStream, pv_eventset, name="eventset") + self._append(DetectorBsStream, pv_eventset, cachannel=None, name="eventset") # EVR output mapping diff --git a/eco/timing/lasertiming_edwin.py b/eco/timing/lasertiming_edwin.py index 2c44702..e4636d6 100644 --- a/eco/timing/lasertiming_edwin.py +++ b/eco/timing/lasertiming_edwin.py @@ -2,6 +2,8 @@ from epics import PV import os import numpy as np import time + +from eco.elements.detector import DetectorVirtual from ..devices_general.utilities import Changer from ..elements.adjustable import ( spec_convenience, @@ -10,7 +12,7 @@ from ..elements.adjustable import ( tweak_option, ) from ..epics.adjustable import AdjustablePv, AdjustablePvEnum -from ..epics.detector import DetectorPvData +from ..epics.detector import DetectorPvData from ..aliases import append_object_to_object, Alias from ..elements.assembly import Assembly @@ -97,9 +99,50 @@ class XltEpics(Assembly): def __init__(self, pvname="SLAAR02-LTIM-PDLY", name="lxt_epics"): super().__init__(name=name) self.pvname = pvname - self.settings_collection.append(self, force=True) - self.status_collection.append(self, force=True) - self.display_collection.append(self, force=True) + # self.settings_collection.append(self, force=True) + # self.status_collection.append(self, force=True) + # self.display_collection.append(self, force=True) + self._append( + AdjustablePv, + self.pvname + ":DELAY_Z_OFFS", + name="_offset", + is_setting=True, + is_display=False, + ) + self._append( + DetectorPvData, + "SLAAR-LGEN:DLY_OFFS2", + unit="µs", + name="delay_dial_rb", + is_setting=False, + is_display=True, + ) + # SLAAR-LGEN:DLY_OFFS2 + self._append( + AdjustableVirtual, + [self._offset], + lambda offset: offset * 1e-12, + lambda offset: offset / 1e-12, + name="offset", + unit="s", + is_setting=False, + is_display=True, + ) + self._append( + DetectorVirtual, + [self.delay_dial_rb, self.offset], + lambda dialrb, offset: dialrb * 1e-6 - offset, + unit="s", + name="readback", + ) + self._append( + AdjustablePv, + self.pvname + ":WINDOW_REQ", + name="phase_shifter_window_start", + is_setting=True, + is_display=True, + unit="ps", + ) self._append( AdjustablePvEnum, self.pvname + ":SHOTDELAY", @@ -115,19 +158,24 @@ class XltEpics(Assembly): is_display=True, ) self._append( - AdjustablePv, - self.pvname + ":DELAY_Z_OFFS", - name="_offset", + AdjustablePvEnum, + self.pvname + ":ONEINN_MODE", + name="reference_mode", is_setting=True, - is_display=False, + is_display=True, ) self._append( - AdjustableVirtual, - [self._offset], - lambda offset: offset * 1e-12, - lambda offset: offset / 1e-12, - name="offset", - is_setting=False, + AdjustablePvEnum, + self.pvname + ":USE_EXT_EVT", + name="use_ext_reference_event", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePv, + self.pvname + ":ALT_EXT_EVT", + name="ext_reference_event", + is_setting=True, is_display=True, ) self._append( @@ -158,18 +206,27 @@ class XltEpics(Assembly): # is_setting=False, # is_display=True, # ) - - self._delay_dial_rb = PV("SLAAR-LGEN:DLY_OFFS2") - self.alias.append( - Alias("delay_dial_rb", "SLAAR-LGEN:DLY_OFFS2", channeltype="CA") - ) + + # self._delay_dial_rb = PV("SLAAR-LGEN:DLY_OFFS2") + # self.alias.append( + # Alias("delay_dial_rb", "SLAAR-LGEN:DLY_OFFS2", channeltype="CA") + # ) self.waiting_for_change = PV(self.pvname + ":WAITING") - def get_current_dial_value(self): - return self._delay_dial_rb.get() * 1e-6 + # def get_current_dial_value(self): + # return self.delay_dial_rb.get_current_value() * 1e-6 - def get_current_value(self): - return self.get_current_dial_value() - self.offset.get_current_value() + # def get_current_value(self): + # return self.get_current_dial_value() - self.offset.get_current_value() + + # def get_current_dial_value(self): + # return self.delay_dial_rb.get_current_value() * 1e-6 + + # def get_current_user_value(self): + # return ( + # self.delay_dial_rb.get_current_value() * 1e-6 + # - self.offset.get_current_value() + # ) def change_user_and_wait(self, value, check_interval=0.03): if np.abs(value) > 0.1: diff --git a/eco/timing/palm.py b/eco/timing/palm.py deleted file mode 100755 index 77b30e5..0000000 --- a/eco/timing/palm.py +++ /dev/null @@ -1,24 +0,0 @@ -from ..devices_general.motors import MotorRecord -from ..devices_general.smaract import SmarActRecord -from epics import PV -from ..devices_general.delay_stage import DelayStage - - -class Palm: - def __init__(self, Id): - self.Id = Id - - self._delayStg = MotorRecord(self.Id + "-M552:MOT") - self.delay = DelayStage(self._delayStg) - - def get_adjustable_positions_str(self): - ostr = "*****Palm motor positions******\n" - - for tkey, item in self.__dict__.items(): - if hasattr(item, "get_current_value"): - pos = item.get_current_value() - ostr += " " + tkey.ljust(10) + " : % 14g\n" % pos - return ostr - - def __repr__(self): - return self.get_adjustable_positions_str() diff --git a/eco/timing/psen.py b/eco/timing/psen.py deleted file mode 100755 index 6336156..0000000 --- a/eco/timing/psen.py +++ /dev/null @@ -1,24 +0,0 @@ -from ..devices_general.motors import MotorRecord -from ..devices_general.smaract import SmarActRecord -from epics import PV -from ..devices_general.delay_stage import DelayStage - - -class Psen: - def __init__(self, Id): - self.Id = Id - - self._delayStg = MotorRecord(self.Id + "-M561:MOT") - self.delay = DelayStage(self._delayStg) - - def get_adjustable_positions_str(self): - ostr = "*****PSEN motor positions******\n" - - for tkey, item in self.__dict__.items(): - if hasattr(item, "get_current_value"): - pos = item.get_current_value() - ostr += " " + tkey.ljust(10) + " : % 14g\n" % pos - return ostr - - def __repr__(self): - return self.get_adjustable_positions_str() diff --git a/eco/timing/sequencer.py b/eco/timing/sequencer.py deleted file mode 100644 index 446287f..0000000 --- a/eco/timing/sequencer.py +++ /dev/null @@ -1,176 +0,0 @@ -from epics.ca import element_count -from epics.pv import PV -import numpy as np -from ..epics.adjustable import AdjustablePv, AdjustablePvEnum -from ..epics.detector import DetectorPvData -from ..elements.detector import DetectorGet -from ..elements.assembly import Assembly - - -class CtaSequencer(Assembly): - def __init__( - self, - pvname, - sequence_number, - event_codes=list(range(200, 220)), - name=None, - ): - super().__init__(name=name) - self.pvname = pvname - self.sequence_number = sequence_number - self.event_codes = event_codes - # self.sequence - self._append( - AdjustablePv, - f"{self.pvname}:SerMaxLen-O", - name="max_length", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePv, self._pvstr("Ctrl-Length-I"), name="length", is_setting=True - ) - self._append( - AdjustablePv, - self._pvstr("Ctrl-Cycles-I"), - name="number_of_repetitions", - is_setting=True, - ) - self._append( - AdjustablePv, - self._pvstr("Ctrl-SCfgMode-I"), - name="start_condition_enabled", - is_setting=True, - ) - self._append( - AdjustablePv, - self._pvstr("Ctrl-SCfgModDivisor-I"), - name="start_condition_pulse_id_divisor", - is_setting=True, - ) - self._append( - AdjustablePv, - self._pvstr("Ctrl-SCfgModOffset-I"), - name="start_condition_pulse_id_offset", - is_setting=True, - ) - self._startpv = PV(self._pvstr("Ctrl-Start-I")) - self._stoppv = PV(self._pvstr("Ctrl-Stop-I")) - self._append( - DetectorPvData, - self._pvstr("Ctrl-IsRunning-O"), - name="is_running", - ) - self._append( - DetectorPvData, - self._pvstr("Ctrl-StartedAt-O"), - name="last_start_pulse_id", - ) - self.event_code_sequences = {} - for i, eventcode in enumerate(self.event_codes): - self._append( - AdjustablePv, - self._pvstr(f"Ser{i}-Data-I"), - # element_count=self.max_length.get_current_value(), - name=f"seq_code{eventcode}", - is_setting=True, - is_display=False, - ) - self.event_code_sequences[eventcode] = self.__dict__[f"seq_code{eventcode}"] - - self._append( - DetectorGet, self.get_reduced_sequence, name="sequence", is_setting=False - ) - - def start(self): - self._startpv.put(1) - - def stop(self): - self._stoppv.put(1) - - def get_sequence_array(self): - arrays = {} - totlen = self.length.get_current_value() - lens = [] - for eventcode, tadj in self.event_code_sequences.items(): - arrays[eventcode] = tadj.get_current_value()[:totlen] - - return arrays - - def append_sequence_step(self, code, step_delay, send_immediately=True): - if code not in self.event_code_sequences.keys(): - raise Exception( - f"Eventcode {code} is not within the allowed or configured eventcodes for the sequencer" - ) - oldlength = self.length.get_current_value() - newlength = oldlength + step_delay - - self.new_sequences = {} - for i, ec in self.event_code_sequences.items(): - if oldlength == 0: - o = [] - else: - o = list(ec.get_current_value()) - if i == code: - ind = newlength - oldlength - 1 - if ind < 0: - o[newlength-1] = 1 - n=o - else: - n = o + [0] * (newlength - oldlength - 1) + [1] - else: - n = o + [0] * (newlength - oldlength) - self.new_sequences[i] = n - # print(o, n) - - if send_immediately: - self.send_new_sequences() - - def send_new_sequences(self): - for i, n in self.new_sequences.items(): - - changes = [] - changes.append(self.event_code_sequences[i].set_target_value(n)) - for change in changes: - change.wait() - - # self.event_code_sequences[code]._value[newlength - 1] = 1 - lengths = [len(n) for i, n in self.new_sequences.items()] - newlength = lengths[0] - print(f"newlength is {newlength}, lengths are {lengths}") - - self.length.set_target_value(newlength).wait() - - def reset_sequence(self): - chs = [] - for code, adj in self.event_code_sequences.items(): - chs.append( - adj.set_target_value( - np.zeros(self.max_length.get_current_value(), dtype=np.int32) - ) - ) - for ch in chs: - ch.wait() - self.length.set_target_value(0).wait() - - def get_reduced_sequence(self): - seq = self.get_sequence_array() - seq_red = {} - for code, is_present_array in seq.items(): - tsteps = is_present_array.nonzero()[0] - for step in tsteps: - if not step in seq_red.keys(): - seq_red[int(step)] = [] - seq_red[step].append(code) - - return seq_red - - def _pvstr(self, suffix=""): - return f"{self.pvname}:seq{self.sequence_number:d}{suffix}" - - -# temp for development - - -def get_cta(): - return CtaSequencer("SAR-CCTA-ESB", 0, name="c") diff --git a/eco/timing/timing_diag.py b/eco/timing/timing_diag.py index 285bbfe..e740616 100644 --- a/eco/timing/timing_diag.py +++ b/eco/timing/timing_diag.py @@ -22,7 +22,7 @@ class TimetoolBerninaUSD(Assembly): self, name=None, processing_pipeline="SARES20-CAMS142-M5_psen_db", - processing_instance="SARES20-CAMS142-M5_psen_db1", + processing_instance="SARES20-CAMS142-M5_psen_db", spectrometer_camera_channel="SARES20-CAMS142-M5:FPICTURE", spectrometer_pvname="SARES20-CAMS142-M5", microscope_pvname="SARES20-PROF141-M1", diff --git a/eco/utilities/recspace.py b/eco/utilities/recspace.py index df2c3ca..c0156a8 100644 --- a/eco/utilities/recspace.py +++ b/eco/utilities/recspace.py @@ -183,8 +183,8 @@ class DiffGeometryYou(Assembly): def new_ub(self): ### missing: clear ub ### ### missing: check ub ### - crystal_name = input(f"Name of the crystal: ({self.name})" or self.name) - a = float(input(f"Lattice constant a ({self.unit_cell()['a']}): ") or {self.unit_cell['a']}) + crystal_name = input(f"Name of the crystal: ({self.name})" or str(self.name)) + a = float(input(f"Lattice constant a (1): ") or 1) b = float(input(f"Lattice constant b ({a}): ") or a) c = float(input(f"Lattice constant c ({a}): ") or a) alpha = float(input("Angle alpha (90): ") or 90) @@ -224,7 +224,7 @@ class DiffGeometryYou(Assembly): self.ubcalc.add_orientation(ori.pop("hkl"), ori.pop("xyz"), **ori) for refl in self.reflections(): position = Position(*refl.pop("position")) - self.ubcalc.add_reflection(refl.pop("hkl"), position, refl.pop("energy"), **refl) + self.ubcalc.add_reflection(refl.pop("hkl"), position, refl.pop("energy")*1e-3, **refl) self._u_ub_to_dc() @@ -311,7 +311,7 @@ class DiffGeometryYou(Assembly): self.recalculate() - def calc_ub(self, idx1=None, idx2=None): + def calc_ub(self, idx1=0, idx2=1): """Calculate UB matrix. Calculate UB matrix using two reference reflections and/or @@ -361,6 +361,9 @@ class DiffGeometryYou(Assembly): Refined U matrix as NumPy array and refined crystal lattice parameters. """ + if refine_lattice: + print("fitting the lattice is not yet implemented") + return setvals = [mu, delta, nu, eta, chi, phi] curvals = self.get_diffractometer_angles() angs = [curval if setval == None else setval for setval, curval in zip(setvals, curvals)] @@ -371,11 +374,9 @@ class DiffGeometryYou(Assembly): self.recalculate() self.ubcalc.refine_ub(hkl, position=position, wavelength=wl, refine_lattice=refine_lattice, refine_umatrix=refine_umatrix) self._u_ub_from_dc() - if refine_lattice: - print("not implemented") - #self._lat_from_dc() - def fit_ub(self, indices, refine_lattice=False, refine_umatrix=False): + + def fit_ub(self, indices=None, refine_lattice=False, refine_umatrix=True): """Refine UB matrix using reference reflections. Parameters @@ -393,7 +394,28 @@ class DiffGeometryYou(Assembly): Refined U matrix as NumPy array and refined crystal lattice parameters. """ self.recalculate() - self.ubcalc.fit_ub(indices, refine_lattice=refine_lattice, refine_umatrix=refine_umatrix) + if indices is None: + indices = list(range(len(self.reflections()))) + ub, lat = self.ubcalc.fit_ub(indices, refine_lattice=refine_lattice, refine_umatrix=refine_umatrix) + if refine_umatrix: + print("\nFitted UB matrix applied") + else: + print("\nFitted UB matrix not applied. To apply it, set refine_umatrix=True") + print(ub) + if refine_lattice: + print("\nFitted lattice applied") + else: + print("\nFitted lattice not applied. To apply it, set refine_lattice=True") + for k, val in { + "name": lat[0], + "a": lat[1], + "b": lat[2], + "c": lat[3], + "alpha": lat[4], + "beta": lat[5], + "gamma": lat[6], + }.items(): + print(f"{k:8}: {val}") self._u_ub_from_dc() if refine_lattice: self._lat_from_dc() @@ -475,7 +497,7 @@ class DiffGeometryYou(Assembly): self.ubcalc.set_u(self.u_matrix()) def _lat_from_dc(self): - self.set_unit_cell(*self.ubcalc.crystal.get_lattice()[1:]) + self.set_unit_cell(*self.ubcalc.crystal.get_lattice()) def en2lam(self, en): """input: energy in eV, returns wavelength in A""" diff --git a/eco/xdiagnostics/intensity_monitors.py b/eco/xdiagnostics/intensity_monitors.py index 2c515df..1c651d6 100755 --- a/eco/xdiagnostics/intensity_monitors.py +++ b/eco/xdiagnostics/intensity_monitors.py @@ -1,4 +1,4 @@ -from ..devices_general.motors import MotorRecord +from ..devices_general.motors import MotorRecord, SmaractRecord from ..devices_general.detectors import FeDigitizer from ..epics.detector import DetectorPvDataStream from ..detector.detectors_psi import DetectorBsStream @@ -82,6 +82,13 @@ class CalibrationRecord(Assembly): is_setting=True, is_display=True, ) + self._append( + AdjustablePv, + self.pvbase + ".INPJ", + name="input_J", + is_setting=True, + is_display=True, + ) self._append( AdjustablePv, @@ -118,13 +125,6 @@ class CalibrationRecord(Assembly): is_setting=True, is_display=True, ) - self._append( - AdjustablePv, - self.pvbase + ".J", - name="const_J", - is_setting=True, - is_display=True, - ) self._append( AdjustablePv, self.pvbase + ".CALC", @@ -158,6 +158,7 @@ class SolidTargetDetectorPBPS(Assembly): use_calibration=True, calibration_records=None, name=None, + fe_digi_channels={}, # calc=None, # calc_calib={}, ): @@ -228,6 +229,31 @@ class SolidTargetDetectorPBPS(Assembly): name="signal_right_raw", is_setting=False, ) + if fe_digi_channels: + self._append( + FeDigitiza, + fe_digi_channels["left"], + name="settings_diode_left", + is_setting=True, + ) + self._append( + FeDigitiza, + fe_digi_channels["right"], + name="settings_diode_right", + is_setting=True, + ) + self._append( + FeDigitiza, + fe_digi_channels["up"], + name="settings_diode_up", + is_setting=True, + ) + self._append( + FeDigitiza, + fe_digi_channels["down"], + name="settings_diode_down", + is_setting=True, + ) if use_calibration: # Calibration calculation record @@ -348,9 +374,9 @@ class SolidTargetDetectorPBPS(Assembly): def set_calibration_values_position(self, xcalib, ycalib): self.calib_xpos.const_I.set_target_value(xcalib) - self.calib_xpos.const_J.set_target_value(0) + # self.calib_xpos.const_J.set_target_value(0) self.calib_ypos.const_I.set_target_value(ycalib) - self.calib_ypos.const_J.set_target_value(0) + # self.calib_ypos.const_J.set_target_value(0) def calibrate(self, seconds=5): c = self.get_calibration_values(seconds=seconds) @@ -1088,3 +1114,253 @@ class SolidTargetDetectorPBPS_assembly(Assembly): return gains except: print("No diodes configured, can not change any gain!") + + +class SolidTargetDetectorBerninaUSD(Assembly): + def __init__( + self, + pv_targets, + # VME_crate=None, + # pipeline=None, + # link=None, + channel_xpos=None, + channel_ypos=None, + channel_intensity=None, + diode_channels_raw={}, + # ch_up=12, + # ch_down=13, + # ch_left=15, + # ch_right=14, + # elog=None, + use_calibration=True, + calibration_records=None, + name=None, + # calc=None, + # calc_calib={}, + ): + super().__init__(name=name) + + self._append( + SmaractRecord, + pv_targets, + name="target_x", + is_setting=True, + is_display=True, + ) + if channel_intensity: + self._append( + DetectorBsStream, + channel_intensity, + name="intensity", + is_setting=False, + ) + + if channel_xpos: + self._append(DetectorBsStream, channel_xpos, name="xpos", is_setting=False) + # else: + # self._append( + # DetectorBsStream, pvname + ":XPOS", name="xpos", is_setting=False + # ) + if channel_ypos: + self._append(DetectorBsStream, channel_ypos, name="ypos", is_setting=False) + # else: + # self._append( + # DetectorBsStream, pvname + ":YPOS", name="ypos", is_setting=False + # ) + + if diode_channels_raw: + self._append( + DetectorBsStream, + diode_channels_raw["up"], + name="signal_up_raw", + is_setting=False, + ) + self._append( + DetectorBsStream, + diode_channels_raw["down"], + name="signal_down_raw", + is_setting=False, + ) + self._append( + DetectorBsStream, + diode_channels_raw["left"], + name="signal_left_raw", + is_setting=False, + ) + self._append( + DetectorBsStream, + diode_channels_raw["right"], + name="signal_right_raw", + is_setting=False, + ) + + if use_calibration: + # Calibration calculation record + + # Calibration + if calibration_records: + self._append( + CalibrationRecord, + calibration_records["intensity"], + name="calib_intensity", + is_setting=True, + is_display=False, + ) + self._append( + CalibrationRecord, + calibration_records["xpos"], + name="calib_xpos", + is_setting=True, + is_display=False, + ) + self._append( + CalibrationRecord, + calibration_records["ypos"], + name="calib_ypos", + is_setting=True, + is_display=False, + ) + + # else: + # self._append( + # CalibrationRecord, + # pvname + ":INTENSITY", + # name="calib_intensity", + # is_setting=True, + # is_display=False, + # ) + # self._append( + # CalibrationRecord, + # pvname + ":XPOS", + # name="calib_xpos", + # is_setting=True, + # is_display=False, + # ) + # self._append( + # CalibrationRecord, + # pvname + ":YPOS", + # name="calib_ypos", + # is_setting=True, + # is_display=False, + # ) + + def get_calibration_values(self, seconds=5): + self.x_diodes.set_target_value(0).wait() + self.y_diodes.set_target_value(0).wait() + ds = [ + self.signal_up_raw, + self.signal_down_raw, + self.signal_left_raw, + self.signal_right_raw, + ] + aqs = [d.acquire(seconds=seconds) for d in ds] + data = [aq.wait() for aq in aqs] + mean = [np.mean(td) for td in data] + std = [np.std(td) for td in data] + nsamples = [len(td) for td in data] + + print(f"Got {nsamples} samples in {seconds} s.") + norm_diodes = [1 / tm / 4 for tm in mean] + return norm_diodes + + def set_calibration_values(self, norm_diodes): + self.calib_intensity.const_E.set_target_value(norm_diodes[0]) + self.calib_ypos.const_E.set_target_value(norm_diodes[0]) + self.calib_intensity.const_F.set_target_value(norm_diodes[1]) + self.calib_ypos.const_F.set_target_value(norm_diodes[1]) + self.calib_intensity.const_G.set_target_value(norm_diodes[2]) + self.calib_xpos.const_E.set_target_value(norm_diodes[2]) + self.calib_intensity.const_H.set_target_value(norm_diodes[3]) + self.calib_xpos.const_F.set_target_value(norm_diodes[3]) + + def get_calibration_values_position( + self, calib_intensities, seconds=5, motion_range=0.2 + ): + self.x_diodes.set_limits(-motion_range / 2 - 0.1, +motion_range / 2 + 0.1) + self.y_diodes.set_limits(-motion_range / 2 - 0.1, +motion_range / 2 + 0.1) + self.x_diodes.set_target_value(0).wait() + self.y_diodes.set_target_value(0).wait() + raw = [] + for pos in [motion_range / 2, -motion_range / 2]: + print(pos) + self.x_diodes.set_target_value(pos).wait() + aqs = [ + ts.acquire(seconds=seconds) + for ts in [self.signal_left_raw, self.signal_right_raw] + ] + vals = [ + np.mean(aq.wait()) * calib + for aq, calib in zip(aqs, calib_intensities[0:2]) + ] + raw.append((vals[0] - vals[1]) / (vals[0] + vals[1])) + xcalib = motion_range / np.diff(raw)[0] + self.x_diodes.set_target_value(0).wait() + raw = [] + for pos in [motion_range / 2, -motion_range / 2]: + self.y_diodes.set_target_value(pos).wait() + aqs = [ + ts.acquire(seconds=seconds) + for ts in [self.signal_up_raw, self.signal_down_raw] + ] + vals = [ + np.mean(aq.wait()) * calib + for aq, calib in zip(aqs, calib_intensities[2:4]) + ] + raw.append((vals[0] - vals[1]) / (vals[0] + vals[1])) + ycalib = motion_range / np.diff(raw)[0] + self.y_diodes.set_target_value(0).wait() + return xcalib, ycalib + + def set_calibration_values_position(self, xcalib, ycalib): + self.calib_xpos.const_I.set_target_value(xcalib) + self.calib_xpos.const_J.set_target_value(0) + self.calib_ypos.const_I.set_target_value(ycalib) + self.calib_ypos.const_J.set_target_value(0) + + def calibrate(self, seconds=5): + c = self.get_calibration_values(seconds=seconds) + self.set_calibration_values(c) + xc, yc = self.get_calibration_values_position(c, seconds=seconds) + self.set_calibration_values_position(xc, yc) + + def set_gains(self, value): + try: + self.diode_up.gain.set(value) + self.diode_down.gain.set(value) + self.diode_left.gain.set(value) + self.diode_right.gain.set(value) + except: + print("No diodes configured, can not change any gain!") + + def get_available_gains(self): + try: + nu = self.diode_up.gain.names + nd = self.diode_down.gain.names + nl = self.diode_left.gain.names + nr = self.diode_right.gain.names + assert ( + nu == nd == nl == nr + ), "NB: the gain options of the four diodes are not equal!!!" + return nu + except: + print("No diodes configured, can not change any gain!") + + def get_gains(self): + try: + gains = dict() + gains["up"] = (self.diode_up.gain.get_name(), self.diode_up.gain.get()) + gains["down"] = ( + self.diode_down.gain.get_name(), + self.diode_down.gain.get(), + ) + gains["left"] = ( + self.diode_left.gain.get_name(), + self.diode_left.gain.get(), + ) + gains["right"] = ( + self.diode_right.gain.get_name(), + self.diode_right.gain.get(), + ) + return gains + except: + print("No diodes configured, can not change any gain!") diff --git a/eco/xdiagnostics/profile_monitors.py b/eco/xdiagnostics/profile_monitors.py index 4f1f029..22f3003 100755 --- a/eco/xdiagnostics/profile_monitors.py +++ b/eco/xdiagnostics/profile_monitors.py @@ -116,27 +116,10 @@ class ProfKbBernina(Assembly): pvname_z="SARES20-MF2:MOT_3", name="target_stages", is_display="recursive", + is_setting=True, ) self.target = self.target_stages.presets - self._append( - MotorRecord, - pvname_target_x, - name="x_target", - is_setting=True, - ) - self._append( - MotorRecord, - pvname_target_y, - name="y_target", - is_setting=True, - ) - self._append( - MotorRecord, - pvname_target_z, - name="z_target", - is_setting=True, - ) self._append( SmaractRecord, pvname_mirror, diff --git a/eco/xdiagnostics/timetools.py b/eco/xdiagnostics/timetools.py index 453a39e..d121297 100644 --- a/eco/xdiagnostics/timetools.py +++ b/eco/xdiagnostics/timetools.py @@ -8,9 +8,17 @@ from ..devices_general.delay_stage import DelayStage from ..aliases import Alias, append_object_to_object from ..loptics.bernina_experiment import DelayTime from cam_server import PipelineClient +from eco import Assembly -class SpectralEncoder: +class TargetStages(Assembly): + def __init__(self,*args,name='target'): + super().__init__(name=name) + for df in args: + self._append(MotorRecord,df[1],name=df[0], is_display=True, is_setting=True) + + +class SpectralEncoder(Assembly): def __init__( self, pvname, @@ -20,36 +28,38 @@ class SpectralEncoder: "spect_tt": "SLAAR21-LMOT-M553:MOT", "retroreflector": "SLAAR21-LMOT-M561:MOT", }, + mirror_stages=None, ): + super().__init__(name=name) self.pvname = pvname - self.name = name - self.alias = Alias(name) - append_object_to_object( - self, MotorRecord, pvname + ":MOTOR_X1", name="x_target" - ) - append_object_to_object( - self, MotorRecord, pvname + ":MOTOR_Y1", name="y_target" - ) + + self._append( + TargetStages, + ('x',pvname + ":MOTOR_X1"), + ('y',pvname + ":MOTOR_Y1"), + name='target_stages', + is_display='recursive', + is_setting=True, + ) + if delay_stages: for key, pv in delay_stages.items(): tname = "delay_" + key + "_stg" - append_object_to_object(self, MotorRecord, pv, name=tname) - append_object_to_object( - self, DelayTime, self.__dict__[tname], name="delay_" + key - ) - - # self.delay = MotorRecord(self.Id + "-M424:MOT") - # self.delayTime = DelayStage(self.delay) - # self.data_reduction_client = PsenProcessingClient( - # address=reduction_client_address - # ) + self._append(MotorRecord, pv, name=tname, is_setting=True) + self._append( + DelayTime, self.__dict__[tname], name="delay_" + key + ) + + if mirror_stages is not None: + for key, pv in mirror_stages.items(): + self._append(MotorRecord, pv, name=key, is_setting=True) # @property # def roi(self): # return self.data_reduction_client.get_roi_signal() # @roi.setter - # def roi(self, values): + # def roi(self, values):tt_opt # self.data_reduction_client.set_roi_signal(values) # @property @@ -60,15 +70,6 @@ class SpectralEncoder: # def roi_background(self, values): # self.data_reduction_client.set_roi_background(values) - def __repr__(self): - s = [f"Status {self.name}"] - s.append(str(self.x_target)) - s.append(str(self.y_target)) - # s.append(f"Data reduction is on") - # s.append(f" roi {self.roi}") - # s.append(f" roi_background {self.roi_background}") - return "\n".join(s) - class SpatialEncoder: def __init__( @@ -76,7 +77,7 @@ class SpatialEncoder: name=None, reduction_client_address="http://sf-daqsync-02:12003/", delay_stages={"spatial_tt": "SLAAR21-LMOT-M522:MOTOR_1"}, - pipeline_id="SARES20-CAMS142-M4_psen_db1", + pipeline_id="SARES20-CAMS142-M4_psen_db", ): self.name = name self.alias = Alias(name) From d1cacf8f5f85c5bb5fdf2d7c636543aa8bb909fa Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Mon, 5 Dec 2022 13:19:59 +0100 Subject: [PATCH 24/52] add monitoring to scans --- eco/bernina/bernina.py | 148 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 0aaf6e4..32e0ac7 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -6,6 +6,9 @@ from eco.elements.adjustable import AdjustableFS from eco.elements.adjustable import AdjustableVirtual from eco.loptics.bernina_experiment import DelayCompensation from eco.devices_general.cameras_swissfel import CameraBasler +from epics import PV +import time +import pickle # from eco.endstations.bernina_sample_environments import Organic_crystal_breadboard_old from eco.motion.smaract import SmaractController @@ -1021,16 +1024,115 @@ def _increment_daq_run_number(scan, daq=daq): print(e) +class Monitor: + def __init__(self, pvname, start_immediately=True): + self.data = {} + self.print = False + self.pv = PV(pvname) + self.cb_index = None + if start_immediately: + self.start_callback() + + def start_callback(self): + self.cb_index = self.pv.add_callback(self.append) + + def stop_callback(self): + self.pv.remove_callback(self.cb_index) + + def append(self, pvname=None, value=None, timestamp=None, **kwargs): + if not (pvname in self.data): + self.data[pvname] = [] + ts_local = time.time() + self.data[pvname].append( + {"value": value, "timestamp": timestamp, "timestamp_local": ts_local} + ) + if self.print: + print( + f"{pvname}: {value}; time: {timestamp}; time_local: {ts_local}; diff: {ts_local-timestamp}" + ) + + +import traceback + + +def append_scan_monitors(scan, daq=daq): + scan.monitors = {} + for adj in scan.adjustables: + try: + tname = adj.alias.get_full_name() + except Exception: + tname = adj.name + traceback.print_exc() + try: + scan.monitors[tname] = Monitor(adj.pvname) + except Exception: + print(f"Could not add CA monitor for {tname}") + traceback.print_exc() + try: + rname = adj.readback.alias.get_full_name() + except Exception: + print("no readback configured") + traceback.print_exc() + try: + scan.monitors[rname] = Monitor(adj.readback.pvname) + except Exception: + print(f"Could not add CA readback monitor for {tname}") + traceback.print_exc() + + try: + tname = daq.pulse_id.alias.get_full_name() + scan.monitors[tname] = Monitor(daq.pulse_id.pvname) + except Exception: + print(f"Could not add daq.pulse_id monitor") + traceback.print_exc() + + +def end_scan_monitors(scan, daq=daq): + for tmon in scan.monitors: + scan.monitors[tmon].stop_callback() + + monitor_result = {tmon: scan.monitors[tmon].data for tmon in scan.monitors} + + ####### + # get data that should come later from api or similar. + run_directory = list( + Path(f"/sf/bernina/data/{daq.pgroup}/raw").glob(f"run{scan.run_number:04d}*") + )[0].as_posix() + + # correct some data in there (relative paths for now) + from os.path import relpath + + # save temprary file and send then to raw + runno = daq.get_last_run_number() + pgroup = daq.pgroup + tmpdir = Path(f"/sf/bernina/data/{pgroup}/res/tmp/info_run{runno:04d}") + tmpdir.mkdir(exist_ok=True, parents=True) + scanmonitorfile = tmpdir / Path("scan_monitor.pkl") + if not Path(scanmonitorfile).exists(): + with open(scanmonitorfile, "wb") as f: + pickle.dump(monitor_result, f) + + print(f"Copying monitor file to run {runno} to the raw directory of {pgroup}.") + response = daq.append_aux( + scanmonitorfile.as_posix(), pgroup=pgroup, run_number=runno + ) + print(f"Status: {response.json()['status']} Message: {response.json()['message']}") + + # scan.monitors = None + + callbacks_start_scan = [] callbacks_start_scan = [lambda scan: namespace.init_all(silent=False)] callbacks_start_scan.append(_wait_for_tasks) callbacks_start_scan.append(_append_namesace_status_to_scan) callbacks_start_scan.append(_increment_daq_run_number) +callbacks_start_scan.append(append_scan_monitors) callbacks_end_scan = [] callbacks_end_scan.append(_write_namespace_status_to_scan) callbacks_end_scan.append(_write_namespace_aliases_to_scan) callbacks_end_scan.append(_copy_scan_info_to_raw) callbacks_end_scan.append(_copy_selected_JF_pedestals_to_raw) +callbacks_end_scan.append(end_scan_monitors) callbacks_end_scan.append(_message_end_scan) @@ -1183,6 +1285,7 @@ namespace.append_obj( # module_name="eco.microscopes", # ) + namespace.append_obj( "CameraBasler", "SARES20-CAMS142-M2", @@ -1252,6 +1355,7 @@ namespace.append_obj( from ..elements.assembly import Assembly from ..devices_general.motors import SmaractStreamdevice +from ..loptics.bernina_laser import DelayTime # namespace.append_obj( @@ -1264,6 +1368,49 @@ from ..devices_general.motors import SmaractStreamdevice from ..epics.adjustable import AdjustablePv + +class Double_Pulse_Pump(Assembly): + def __init__(self, name=None): + super().__init__(name=name) + + ### dp smaract stages #### + + self.motor_configuration = { + "delaystage_both": { + "id": "SARES23:ESB15", + }, + "delaystage_pulse2": { + "id": "SARES23:ESB1", + }, + "wp_both": { + "id": "SARES23:ESB3", + }, + "wp_pulse2": { + "id": "SARES23:ESB2", + }, + } + for name, config in self.motor_configuration.items(): + self._append( + SmaractRecord, + pvname=config["id"], + name=name, + is_setting=True, + ) + self._append( + DelayTime, self.delaystage_both, name="delay_both", is_setting=True + ) + self._append( + DelayTime, self.delaystage_pulse2, name="delay_pulse2", is_setting=True + ) + + +namespace.append_obj( + Double_Pulse_Pump, + lazy=True, + name="pump", +) + + # ad hoc N2 jet readout class N2jet(Assembly): def __init__(self, name=None): @@ -1335,6 +1482,7 @@ namespace.append_obj( name="thc", lazy=True, module_name="eco.endstations.bernina_sample_environments", + configuration=["ottifant"], ) From 195575c0cc003d163bf6459bce671df43180355b Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Mon, 5 Dec 2022 16:17:01 +0100 Subject: [PATCH 25/52] added monitoring functionality for CA on assemblies --- eco/aliases/aliases.py | 20 +++++++------ eco/elements/assembly.py | 62 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 69 insertions(+), 13 deletions(-) diff --git a/eco/aliases/aliases.py b/eco/aliases/aliases.py index fc0a17e..baf0de6 100644 --- a/eco/aliases/aliases.py +++ b/eco/aliases/aliases.py @@ -33,7 +33,7 @@ class Alias: o = self.children[i] o.parent = None - def get_all(self, joiner="."): + def get_all(self, joiner=".", channeltypes=None): aa = [] if self.channel: ta = {} @@ -41,18 +41,20 @@ class Alias: ta["channel"] = self.channel if self.channeltype: ta["channeltype"] = self.channeltype - aa.append(ta) + if (not channeltypes) or (ta["channeltype"] in channeltypes): + aa.append(ta) if self.children: for tc in self.children: taa = tc.get_all() for ta in taa: - aa.append( - { - "alias": joiner.join([self.alias, ta["alias"]]), - "channel": ta["channel"], - "channeltype": ta["channeltype"], - } - ) + if (not channeltypes) or (ta["channeltype"] in channeltypes): + aa.append( + { + "alias": joiner.join([self.alias, ta["alias"]]), + "channel": ta["channel"], + "channeltype": ta["channeltype"], + } + ) return aa def get_full_name(self, base=None, joiner="."): diff --git a/eco/elements/assembly.py b/eco/elements/assembly.py index f035d45..52b686a 100644 --- a/eco/elements/assembly.py +++ b/eco/elements/assembly.py @@ -110,11 +110,13 @@ class Assembly: if view_toplevel_only: self.view_toplevel_only.append(self.__dict__[name]) - def get_status(self, base="self", verbose=True): + def get_status(self, base="self", verbose=True, channeltypes=None): if base == "self": base = self settings = {} + settings_channels = {} status = {} + status_channels = {} nodet = [] geterror = [] for ts in track( @@ -129,7 +131,16 @@ class Assembly: # else: if hasattr(ts, "get_current_value"): try: - settings[ts.alias.get_full_name(base=base)] = ts.get_current_value() + if (not channeltypes) or (ts.alias.channeltype in channeltypes): + settings[ + ts.alias.get_full_name(base=base) + ] = ts.get_current_value() + try: + settings_channels[ + ts.alias.get_full_name(base=base) + ] = ts.alias.channel + except: + pass except: geterror.append(ts.alias.get_full_name(base=base)) else: @@ -146,7 +157,16 @@ class Assembly: # else: if hasattr(ts, "get_current_value"): try: - status[ts.alias.get_full_name(base=base)] = ts.get_current_value() + if (not channeltypes) or (ts.alias.channeltype in channeltypes): + status[ + ts.alias.get_full_name(base=base) + ] = ts.get_current_value() + try: + status_channels[ + ts.alias.get_full_name(base=base) + ] = ts.alias.channel + except: + pass except: geterror.append(ts.alias.get_full_name(base=base)) else: @@ -159,7 +179,12 @@ class Assembly: "Retrieved error while running get_current_value from: " + ", ".join(geterror) ) - return {"settings": settings, "status": status} + return { + "settings": settings, + "status": status, + "settings_channels": settings_channels, + "status_channels": status_channels, + } def status(self, get_string=False): stat = self.get_status() @@ -244,6 +269,35 @@ class Assembly: subprocess.Popen(line, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) +import epics.pv +import time + + +class Monitor: + def __init__(self, assembly): + self.assembly = assembly + self.data = {} + self.callbacks = {} + + def start_monitoring(self): + o = self.assembly.get_status(channeltypes=["CA"]) + self.data = {k: [v] for k, v in o["status"].items()} + self.channelkeys = {v: k for k, v in o["status_channels"].items()} + for cik, civ in epics.pv._PVcache_.items(): + if cik[0] in o["status_channels"].keys(): + tname = self.channelkeys[cik[0]] + tpv = civ + self.callbacks[tname] = tpv.add_callback(self.append) + + def append(self, pvname=None, value=None, timestamp=None, **kwargs): + if not (pvname in self.data): + self.data[pvname] = [] + ts_local = time.time() + self.data[self.channelkeys[pvname]].append( + {"value": value, "timestamp": timestamp, "timestamp_local": ts_local} + ) + + class Assembly_old: def __init__(self, name=None, parent=None, is_alias=True): self.name = name From 9f58ddb768e5e1fb664686f5ffa94abd4862b233 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Fri, 20 Jan 2023 21:59:55 +0100 Subject: [PATCH 26/52] fixes --- eco/bernina/bernina.py | 11 +- eco/dbase/strip_chart.py | 19 + eco/detector/detectors_psi.py | 5 + eco/elements/adjustable.py | 31 +- eco/elements/assembly.py | 23 +- eco/endstations/bernina_diffractometers.py | 2 +- eco/loptics/bernina_laser.py | 37 +- eco/timing/lasertiming_edwin.py | 230 +++++++---- eco/timing/sequencer.py | 176 +++++++++ eco/timing/timing_diag.py | 9 + eco/utilities/recspace.py | 429 +++++++++++++++------ eco/xdiagnostics/profile_monitors.py | 2 + eco/xoptics/reflaser.py | 2 +- 13 files changed, 757 insertions(+), 219 deletions(-) create mode 100644 eco/dbase/strip_chart.py create mode 100644 eco/timing/sequencer.py diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 32e0ac7..0167042 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -61,6 +61,13 @@ namespace.append_obj( lazy=False, ) +namespace.append_obj( + "get_strip_chart_function", + name="strip_chart", + module_name="eco.dbase.strip_chart", + lazy=True, +) + namespace.append_obj( "EventWorker", name="bs_worker", @@ -286,7 +293,7 @@ namespace.append_obj( namespace.append_obj( "RefLaser_Aramis", - "SAROP21-OLAS136", + "SAROP21-OLAS134", module_name="eco.xoptics.reflaser", name="reflaser", lazy=True, @@ -630,7 +637,7 @@ namespace.append_obj( ) namespace.append_obj( "SlitPosWidth", - "SAROP21-OAPU136", + "SAROP21-OAPU138", name="slit_att", module_name="eco.xoptics.slits", ), diff --git a/eco/dbase/strip_chart.py b/eco/dbase/strip_chart.py new file mode 100644 index 0000000..dbb687f --- /dev/null +++ b/eco/dbase/strip_chart.py @@ -0,0 +1,19 @@ +import subprocess, os + + +def get_strip_chart_function(): + return strip_chart + + +def strip_chart(*args, **kwargs): + """Usage: Arguments represent channels in the strip_chart config command line argument. + Alternatively arguments can be detectors or adjustables, from which _all_ channels are determined + """ + channels = list(args) + cmd = ["strip_chart"] + cmd += ['-config="' + str(channels) + '"'] + cmd += ["-start"] + line = " ".join(cmd) + print(f"Starting following commandline silently:\n" + line) + with open(os.devnull, "w") as FNULL: + subprocess.Popen(line, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) diff --git a/eco/detector/detectors_psi.py b/eco/detector/detectors_psi.py index 742e1f6..817049d 100644 --- a/eco/detector/detectors_psi.py +++ b/eco/detector/detectors_psi.py @@ -25,6 +25,11 @@ class DetectorBsStream: self.stream = stream.EscData(source=stream.EventSource(self.bs_channel, None)) + def bs_avail(self): + return self.bs_channel in [ + tmp["name"] for tmp in dispatcher.get_current_channels() + ] + def get_current_value(self, force_bsstream=False): if not force_bsstream: diff --git a/eco/elements/adjustable.py b/eco/elements/adjustable.py index 6d1ad5c..ab07398 100644 --- a/eco/elements/adjustable.py +++ b/eco/elements/adjustable.py @@ -168,8 +168,8 @@ class ValueInRange: def update_changes(Adj): def get_position_str(start, end, value): - vals = [v if hasattr(v,"__iter__") else [v] for v in [start, end, value]] -# bars = [] + vals = [v if hasattr(v, "__iter__") else [v] for v in [start, end, value]] + # bars = [] bars = "" for s, v, e in zip(*vals): s = float(s) @@ -184,14 +184,14 @@ def update_changes(Adj): + s + 2 * "\t" ) -# bars.append(( -# colorama.Style.BRIGHT -# + f"{v:1.5}".rjust(10) -# + colorama.Style.RESET_ALL -# + " " -# + s -# + 2 * "\t" -# )) + # bars.append(( + # colorama.Style.BRIGHT + # + f"{v:1.5}".rjust(10) + # + colorama.Style.RESET_ALL + # + " " + # + s + # + 2 * "\t" + # )) return bars def update_change(self, value, elog=None): @@ -202,7 +202,7 @@ def update_changes(Adj): ) except TypeError: print(f"Changing {self.name} from {start} to {value}") - #for pos in get_position_str(start, value, start): + # for pos in get_position_str(start, value, start): # print(pos, end="\r") print(get_position_str(start, value, start), end="\r") try: @@ -210,7 +210,7 @@ def update_changes(Adj): def cbfoo(**kwargs): present_value = self.get_current_value() - #for pos in get_position_str(start, value, present_value): + # for pos in get_position_str(start, value, present_value): # print(pos, end="\r") print(get_position_str(start, value, present_value), end="\r") @@ -263,7 +263,10 @@ def value_property(Adj, wait_for_change=True, value_name="_value"): if wait_for_change: def set_target_value_wait(self, value): - self.set_target_value(value, hold=False).wait() + try: + self.set_target_value(value, hold=False).wait() + except: + self.set_target_value(value).wait() def get_current_value(self): o = self.get_current_value() @@ -556,7 +559,7 @@ class AdjustableGetSet: else: self._set(value) - def set_target_value(self, value): + def set_target_value(self, value, hold=False): return Changer( target=value, parent=self, diff --git a/eco/elements/assembly.py b/eco/elements/assembly.py index 52b686a..9987570 100644 --- a/eco/elements/assembly.py +++ b/eco/elements/assembly.py @@ -278,20 +278,27 @@ class Monitor: self.assembly = assembly self.data = {} self.callbacks = {} + self.pvs = {} def start_monitoring(self): o = self.assembly.get_status(channeltypes=["CA"]) - self.data = {k: [v] for k, v in o["status"].items()} + # self.data = {k: [v] for k, v in o["status"].items()} self.channelkeys = {v: k for k, v in o["status_channels"].items()} - for cik, civ in epics.pv._PVcache_.items(): - if cik[0] in o["status_channels"].keys(): - tname = self.channelkeys[cik[0]] - tpv = civ - self.callbacks[tname] = tpv.add_callback(self.append) + self.pvs = {k: epics.pv.PV(v) for k, v in o["status_channels"].items()} + # for cik, civ in epics.pv._PVcache_.items(): + # if cik[0] in o["status_channels"].keys(): + # tname = self.channelkeys[cik[0]] + # tpv = civ + for tname, tpv in self.pvs.items(): + self.callbacks[tname] = tpv.add_callback(self.append) + + def stop_monitoring(self): + for tname in self.pvs: + self.pvs[tname].remove_callback(index=self.callbacks[tname]) def append(self, pvname=None, value=None, timestamp=None, **kwargs): - if not (pvname in self.data): - self.data[pvname] = [] + if not (self.channelkeys[pvname] in self.data): + self.data[self.channelkeys[pvname]] = [] ts_local = time.time() self.data[self.channelkeys[pvname]].append( {"value": value, "timestamp": timestamp, "timestamp_local": ts_local} diff --git a/eco/endstations/bernina_diffractometers.py b/eco/endstations/bernina_diffractometers.py index 7388740..cae5402 100644 --- a/eco/endstations/bernina_diffractometers.py +++ b/eco/endstations/bernina_diffractometers.py @@ -570,7 +570,7 @@ class XRDYou(Assembly): try: self._append( MotorRecord_new, - Id + ":MOT_TBL_RY", + Id + ":MOT_TBL_RZ", name="rzhl", is_setting=True, is_display=True, diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index 910acea..61362a4 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -30,11 +30,31 @@ class Spectrometer(Assembly): def __init__(self, pvname, name=None): super().__init__(name=name) self.pvname = pvname - self._append(self, AdjustablePvEnum, pvname + ":TRIGGER", name="trigger_mode") - self._append(self, AdjustablePvEnum, pvname + ":INIT", name="state") - self._append(self, AdjustablePv, pvname + ":EXPOSURE", name="exposure_time") - self._append(self, AdjustablePv, pvname + ":EXPOSURE", name="exposure_time") - self._append(self, DetectorPvData, pvname + ":CENTRE", name="center") + self._append( + AdjustablePvEnum, + pvname + ":TRIGGER", + name="trigger_mode", + is_setting=True, + ) + self._append(AdjustablePvEnum, pvname + ":INIT", name="state", is_setting=True) + self._append( + AdjustablePv, + pvname + ":EXPOSURE", + name="exposure_time", + is_setting=True, + ) + self._append(DetectorPvData, pvname + ":CENTRE", name="center") + self._append(DetectorPvData, pvname + ":FWHM", name="fwhm") + self._append(DetectorPvData, pvname + ":AMPLITUDE", name="amplitude") + self._append(DetectorPvData, pvname + ":INTEGRAL", name="integral") + self._append(DetectorPvData, pvname + ":BASER_HEIGHT", name="base_value") + self._append( + AdjustablePv, pvname + ":XVAL1", name="spectrum_min", is_setting=True + ) + self._append( + AdjustablePv, pvname + ":XVAL2", name="spectrum_max", is_setting=True + ) + # SLAAR02-LSPC-OSC:SERIALNR flag_names_filter_wheel = [ @@ -169,6 +189,13 @@ class LaserBernina(Assembly): name="wp_att_calibration", is_display=False, ) + self._append( + Spectrometer, + "SLAAR02-LSPC-OSC", + name="oscillator_spectrum", + is_setting=False, + is_display=True, + ) def uJ2wp(uJ): direction = 1 diff --git a/eco/timing/lasertiming_edwin.py b/eco/timing/lasertiming_edwin.py index e4636d6..a8a2224 100644 --- a/eco/timing/lasertiming_edwin.py +++ b/eco/timing/lasertiming_edwin.py @@ -17,80 +17,153 @@ from ..aliases import append_object_to_object, Alias from ..elements.assembly import Assembly -@spec_convenience -class XltEpics: - def __init__(self, pvname="SLAAR02-LTIM-PDLY", name="lxt_epics"): - self.pvname = pvname - self.alias = Alias(name) - append_object_to_object( - self, - AdjustablePvEnum, - self.pvname + ":SHOTDELAY", - name="oscialltor_pulse_offset", - ) - append_object_to_object( - self, - AdjustablePvEnum, - self.pvname + ":SHOTMOFFS_ENA", - name="modulo_offset_mode", - ) - append_object_to_object( - self, AdjustablePv, self.pvname + ":DELAY_Z_OFFS", name="_offset" - ) - self.offset = AdjustableVirtual( - [self._offset], - lambda offset: offset * 1e-12, - lambda offset: offset / 1e-12, - name="offset", - ) - append_object_to_object( - self, AdjustablePv, self.pvname + ":DELAY", name="_set_user_delay_value" - ) - self._delay_dial_rb = PV("SLAAR-LGEN:DLY_OFFS2") - self.alias.append( - Alias("delay_dial_rb", "SLAAR-LGEN:DLY_OFFS2", channeltype="CA") - ) - self.waiting_for_change = PV(self.pvname + ":WAITING") +# @spec_convenience +# class XltEpics: +# def __init__(self, pvname="SLAAR02-LTIM-PDLY", name="lxt_epics"): +# self.pvname = pvname +# self.alias = Alias(name) +# append_object_to_object( +# self, +# AdjustablePvEnum, +# self.pvname + ":SHOTDELAY", +# name="oscialltor_pulse_offset", +# ) +# append_object_to_object( +# self, +# AdjustablePvEnum, +# self.pvname + ":SHOTMOFFS_ENA", +# name="modulo_offset_mode",@spec_convenience +# class XltEpics: +# def __init__(self, pvname="SLAAR02-LTIM-PDLY", name="lxt_epics"): +# self.pvname = pvname +# self.alias = Alias(name) +# append_object_to_object( +# self, +# AdjustablePvEnum, +# self.pvname + ":SHOTDELAY", +# name="oscialltor_pulse_offset", +# ) +# append_object_to_object( +# self, +# AdjustablePvEnum, +# self.pvname + ":SHOTMOFFS_ENA", +# name="modulo_offset_mode", +# ) +# append_object_to_object( +# self, AdjustablePv, self.pvname + ":DELAY_Z_OFFS", name="_offset" +# ) +# self.offset = AdjustableVirtual( +# [self._offset], +# lambda offset: offset * 1e-12, +# lambda offset: offset / 1e-12, +# name="offset", +# ) +# append_object_to_object( +# self, AdjustablePv, self.pvname + ":DELAY", name="_set_user_delay_value" +# ) +# self._delay_dial_rb = PV("SLAAR-LGEN:DLY_OFFS2") +# self.alias.append( +# Alias("delay_dial_rb", "SLAAR-LGEN:DLY_OFFS2", channeltype="CA") +# ) +# self.waiting_for_change = PV(self.pvname + ":WAITING") - def get_current_dial_value(self): - return self._delay_dial_rb.get() * 1e-6 +# def get_current_dial_value(self): +# return self._delay_dial_rb.get() * 1e-6 - def get_current_value(self): - return self.get_current_dial_value() - self.offset.get_current_value() +# def get_current_value(self): +# return self.get_current_dial_value() - self.offset.get_current_value() - def change_user_and_wait(self, value, check_interval=0.03): - if np.abs(value) > 0.1: - raise Exception("Very large value! This value is counted in seconds!") - if not self.waiting_for_change.get(): - raise Exception("lxt is still moving!") - self.is_moving = False - self.is_stopped = False +# def change_user_and_wait(self, value, check_interval=0.03): +# if np.abs(value) > 0.1: +# raise Exception("Very large value! This value is counted in seconds!") +# if not self.waiting_for_change.get(): +# raise Exception("lxt is still moving!") +# self.is_moving = False +# self.is_stopped = False - def set_is_stopped(**kwargs): - old_status = self.is_moving - new_status = not bool(kwargs["value"]) - if (not new_status) and old_status: - self.is_stopped = True - self.is_moving = new_status +# def set_is_stopped(**kwargs): +# old_status = self.is_moving +# new_status = not bool(kwargs["value"]) +# if (not new_status) and old_status: +# self.is_stopped = True +# self.is_moving = new_status - self.waiting_for_change.add_callback(callback=set_is_stopped) - self._set_user_delay_value.set_target_value(value / 1e-12) +# self.waiting_for_change.add_callback(callback=set_is_stopped) +# self._set_user_delay_value.set_target_value(value / 1e-12) - while not self.is_stopped: - time.sleep(check_interval) - self.waiting_for_change.clear_callbacks() +# while not self.is_stopped: +# time.sleep(check_interval) +# self.waiting_for_change.clear_callbacks() - def set_target_value(self, value, hold=False): - return Changer( - target=value, - parent=self, - changer=self.change_user_and_wait, - hold=hold, - stopper=None, - ) +# def set_target_value(self, value, hold=False): +# return Changer( +# target=value, +# parent=self, +# changer=self.change_user_and_wait, +# hold=hold, +# stopper=None, +# ) - def reset_current_value_to(self, value): - self.offset.set_target_value((self.get_current_dial_value() - value)).wait() +# def reset_current_value_to(self, value): +# self.offset.set_target_value((self.get_current_dial_value() - value)).wait() +# ) +# append_object_to_object( +# self, AdjustablePv, self.pvname + ":DELAY_Z_OFFS", name="_offset" +# ) +# self.offset = AdjustableVirtual( +# [self._offset], +# lambda offset: offset * 1e-12, +# lambda offset: offset / 1e-12, +# name="offset", +# ) +# append_object_to_object( +# self, AdjustablePv, self.pvname + ":DELAY", name="_set_user_delay_value" +# ) +# self._delay_dial_rb = PV("SLAAR-LGEN:DLY_OFFS2") +# self.alias.append( +# Alias("delay_dial_rb", "SLAAR-LGEN:DLY_OFFS2", channeltype="CA") +# ) +# self.waiting_for_change = PV(self.pvname + ":WAITING") + +# def get_current_dial_value(self): +# return self._delay_dial_rb.get() * 1e-6 + +# def get_current_value(self): +# return self.get_current_dial_value() - self.offset.get_current_value() + +# def change_user_and_wait(self, value, check_interval=0.03): +# if np.abs(value) > 0.1: +# raise Exception("Very large value! This value is counted in seconds!") +# if not self.waiting_for_change.get(): +# raise Exception("lxt is still moving!") +# self.is_moving = False +# self.is_stopped = False + +# def set_is_stopped(**kwargs): +# old_status = self.is_moving +# new_status = not bool(kwargs["value"]) +# if (not new_status) and old_status: +# self.is_stopped = True +# self.is_moving = new_status + +# self.waiting_for_change.add_callback(callback=set_is_stopped) +# self._set_user_delay_value.set_target_value(value / 1e-12) + +# while not self.is_stopped: +# time.sleep(check_interval) +# self.waiting_for_change.clear_callbacks() + +# def set_target_value(self, value, hold=False): +# return Changer( +# target=value, +# parent=self, +# changer=self.change_user_and_wait, +# hold=hold, +# stopper=None, +# ) + +# def reset_current_value_to(self, value): +# self.offset.set_target_value((self.get_current_dial_value() - value)).wait() @spec_convenience @@ -113,9 +186,9 @@ class XltEpics(Assembly): DetectorPvData, "SLAAR-LGEN:DLY_OFFS2", unit="µs", - name="delay_dial_rb", + name="delay_user_rb", is_setting=False, - is_display=True, + is_display=False, ) # SLAAR-LGEN:DLY_OFFS2 self._append( @@ -130,8 +203,8 @@ class XltEpics(Assembly): ) self._append( DetectorVirtual, - [self.delay_dial_rb, self.offset], - lambda dialrb, offset: dialrb * 1e-6 - offset, + [self.delay_user_rb], + lambda dialrb: dialrb * 1e-6, unit="s", name="readback", ) @@ -181,7 +254,7 @@ class XltEpics(Assembly): self._append( AdjustablePv, self.pvname + ":DELAY", - name="_set_user_delay_value", + name="_set_dial_delay_value", is_setting=False, is_display=False, ) @@ -216,8 +289,8 @@ class XltEpics(Assembly): # def get_current_dial_value(self): # return self.delay_dial_rb.get_current_value() * 1e-6 - # def get_current_value(self): - # return self.get_current_dial_value() - self.offset.get_current_value() + def get_current_value(self): + return self.readback.get_current_value() # def get_current_dial_value(self): # return self.delay_dial_rb.get_current_value() * 1e-6 @@ -244,7 +317,9 @@ class XltEpics(Assembly): self.is_moving = new_status self.waiting_for_change.add_callback(callback=set_is_stopped) - self._set_user_delay_value.set_target_value(value / 1e-12) + self._set_dial_delay_value.set_target_value( + (value - self.offset.get_current_value()) / 1e-12 + ) while not self.is_stopped: time.sleep(check_interval) @@ -261,3 +336,10 @@ class XltEpics(Assembly): def reset_current_value_to(self, value): self.offset.set_target_value((self.get_current_dial_value() - value)).wait() + + # caqtdm -noMsg -macro S=SLAAR02-LTIM-PDLY /sf/laser/config/qt/SLAAR02-L-SET_DELAY.ui + + def gui(self): + self._run_cmd( + f"caqtdm -noMsg -macro S=SLAAR02-LTIM-PDLY /sf/laser/config/qt/SLAAR02-L-SET_DELAY.ui" + ) diff --git a/eco/timing/sequencer.py b/eco/timing/sequencer.py new file mode 100644 index 0000000..e27eacf --- /dev/null +++ b/eco/timing/sequencer.py @@ -0,0 +1,176 @@ +from epics.ca import element_count +from epics.pv import PV +import numpy as np +from ..epics.adjustable import AdjustablePv, AdjustablePvEnum +from ..epics.detector import DetectorPvData +from ..elements.detector import DetectorGet +from ..elements.assembly import Assembly + + +class CtaSequencer(Assembly): + def __init__( + self, + pvname, + sequence_number, + event_codes=list(range(200, 220)), + name=None, + ): + super().__init__(name=name) + self.pvname = pvname + self.sequence_number = sequence_number + self.event_codes = event_codes + # self.sequence + self._append( + AdjustablePv, + f"{self.pvname}:SerMaxLen-O", + name="max_length", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, self._pvstr("Ctrl-Length-I"), name="length", is_setting=True + ) + self._append( + AdjustablePv, + self._pvstr("Ctrl-Cycles-I"), + name="number_of_repetitions", + is_setting=True, + ) + self._append( + AdjustablePv, + self._pvstr("Ctrl-SCfgMode-I"), + name="start_condition_enabled", + is_setting=True, + ) + self._append( + AdjustablePv, + self._pvstr("Ctrl-SCfgModDivisor-I"), + name="start_condition_pulse_id_divisor", + is_setting=True, + ) + self._append( + AdjustablePv, + self._pvstr("Ctrl-SCfgModOffset-I"), + name="start_condition_pulse_id_offset", + is_setting=True, + ) + self._startpv = PV(self._pvstr("Ctrl-Start-I")) + self._stoppv = PV(self._pvstr("Ctrl-Stop-I")) + self._append( + DetectorPvData, + self._pvstr("Ctrl-IsRunning-O"), + name="is_running", + ) + self._append( + DetectorPvData, + self._pvstr("Ctrl-StartedAt-O"), + name="last_start_pulse_id", + ) + self.event_code_sequences = {} + for i, eventcode in enumerate(self.event_codes): + self._append( + AdjustablePv, + self._pvstr(f"Ser{i}-Data-I"), + # element_count=self.max_length.get_current_value(), + name=f"seq_code{eventcode}", + is_setting=True, + is_display=False, + ) + self.event_code_sequences[eventcode] = self.__dict__[f"seq_code{eventcode}"] + + self._append( + DetectorGet, self.get_reduced_sequence, name="sequence", is_setting=False + ) + + def start(self): + self._startpv.put(1) + + def stop(self): + self._stoppv.put(1) + + def get_sequence_array(self): + arrays = {} + totlen = self.length.get_current_value() + lens = [] + for eventcode, tadj in self.event_code_sequences.items(): + arrays[eventcode] = tadj.get_current_value()[:totlen] + + return arrays + + def append_sequence_step(self, code, step_delay, send_immediately=True): + if code not in self.event_code_sequences.keys(): + raise Exception( + f"Eventcode {code} is not within the allowed or configured eventcodes for the sequencer" + ) + oldlength = self.length.get_current_value() + newlength = oldlength + step_delay + + self.new_sequences = {} + for i, ec in self.event_code_sequences.items(): + if oldlength == 0: + o = [] + else: + o = list(ec.get_current_value()) + if i == code: + ind = newlength - oldlength - 1 + if ind < 0: + o[newlength - 1] = 1 + n = o + else: + n = o + [0] * (newlength - oldlength - 1) + [1] + else: + n = o + [0] * (newlength - oldlength) + self.new_sequences[i] = n + # print(o, n) + + if send_immediately: + self.send_new_sequences() + + def send_new_sequences(self): + for i, n in self.new_sequences.items(): + + changes = [] + changes.append(self.event_code_sequences[i].set_target_value(n)) + for change in changes: + change.wait() + + # self.event_code_sequences[code]._value[newlength - 1] = 1 + lengths = [len(n) for i, n in self.new_sequences.items()] + newlength = lengths[0] + print(f"newlength is {newlength}, lengths are {lengths}") + + self.length.set_target_value(newlength).wait() + + def reset_sequence(self): + chs = [] + for code, adj in self.event_code_sequences.items(): + chs.append( + adj.set_target_value( + np.zeros(self.max_length.get_current_value(), dtype=np.int32) + ) + ) + for ch in chs: + ch.wait() + self.length.set_target_value(0).wait() + + def get_reduced_sequence(self): + seq = self.get_sequence_array() + seq_red = {} + for code, is_present_array in seq.items(): + tsteps = is_present_array.nonzero()[0] + for step in tsteps: + if not step in seq_red.keys(): + seq_red[int(step)] = [] + seq_red[step].append(code) + + return seq_red + + def _pvstr(self, suffix=""): + return f"{self.pvname}:seq{self.sequence_number:d}{suffix}" + + +# temp for development + + +def get_cta(): + return CtaSequencer("SAR-CCTA-ESB", 0, name="c") diff --git a/eco/timing/timing_diag.py b/eco/timing/timing_diag.py index e740616..88c2365 100644 --- a/eco/timing/timing_diag.py +++ b/eco/timing/timing_diag.py @@ -1,3 +1,4 @@ +from eco.detector.detectors_psi import DetectorBsStream from ..elements.assembly import Assembly from ..devices_general.motors import SmaractStreamdevice, MotorRecord, SmaractRecord from ..elements.adjustable import AdjustableMemory, AdjustableVirtual @@ -127,6 +128,14 @@ class TimetoolBerninaUSD(Assembly): accuracy=10, is_setting=True, ) + self._append( + DetectorBsStream, + "SAROP21-ATT01:arrival_time", + cachannel=None, + name="edge_position", + is_setting=False, + is_display=True, + ) def get_online_data(self): self.online_monitor = TtProcessor() diff --git a/eco/utilities/recspace.py b/eco/utilities/recspace.py index c0156a8..760bb8a 100644 --- a/eco/utilities/recspace.py +++ b/eco/utilities/recspace.py @@ -15,6 +15,7 @@ from typing import Tuple, Optional from eco.elements.adj_obj import AdjustableObject from epics import PV + class CrystalNew(Assembly): def __init__(self, *args, name=None, **kwargs): Assembly.__init__(self, name=name) @@ -42,17 +43,36 @@ class Crystals(Assembly): def __init__(self, diffractometer_you=None, name=None): super().__init__(name=name) self.diffractometer = diffractometer_you - self._append(AdjustableFS, f'/photonics/home/gac-bernina/eco/configuration/crystals/{name}_list', name="crystal_list", default_value={}, is_setting=True) + self._append( + AdjustableFS, + f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_list", + name="crystal_list", + default_value={}, + is_setting=True, + ) for key, date in self.crystal_list().items(): - self._append(DiffGeometryYou, diffractometer_you=self.diffractometer, name=key) + self._append( + DiffGeometryYou, diffractometer_you=self.diffractometer, name=key + ) + def append_crystal(self, name=None): - if name==None: - name = input("Please choose a name for your crystal (no spaces or other special characters):") + if name == None: + name = input( + "Please choose a name for your crystal (no spaces or other special characters):" + ) specials = np.array([" ", "/", "(", ")", "[", "]"]) in_name = np.array([s in name for s in specials]) if np.any(in_name): - raise Exception(f"Special character(s) {specials[in_name]} in name not allowed") - self._append(DiffGeometryYou, diffractometer_you=self.diffractometer, name=name, is_setting=True, is_display=False) + raise Exception( + f"Special character(s) {specials[in_name]} in name not allowed" + ) + self._append( + DiffGeometryYou, + diffractometer_you=self.diffractometer, + name=name, + is_setting=True, + is_display=False, + ) crystals = self.crystal_list() crystals[name] = str(datetime.now()) self.crystal_list.mv(crystals) @@ -62,22 +82,40 @@ class Crystals(Assembly): """ Remove crystal with a given name, deletes also the files. """ - sure = 'n' - sure = input(f"are you sure you want to permanently remove the crystal {name} and its UB matrix and memories (y/n)? ") - if sure == 'y': + sure = "n" + sure = input( + f"are you sure you want to permanently remove the crystal {name} and its UB matrix and memories (y/n)? " + ) + if sure == "y": crystals = self.crystal_list() removed = crystals.pop(name) self.crystal_list.mv(crystals) - attrs = ["unit_cell", "u_matrix", "ub_matrix", "orientations", "reflections", "constraints"] + attrs = [ + "unit_cell", + "u_matrix", + "ub_matrix", + "orientations", + "reflections", + "constraints", + ] for a in attrs: - if os.path.exists(f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_{a}"): - os.remove(f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_{a}") + if os.path.exists( + f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_{a}" + ): + os.remove( + f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_{a}" + ) + class DiffGeometryYou(Assembly): def __init__(self, diffractometer_you=None, name=None): super().__init__(name=name) # self._append(diffractometer_you,call_obj=False, name='diffractometer') - self._append(AdjustableFS, f'/photonics/home/gac-bernina/eco/configuration/crystals/{name}_unit_cell', name="unit_cell", default_value={ + self._append( + AdjustableFS, + f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_unit_cell", + name="unit_cell", + default_value={ "name": name, "a": 1, "b": 1, @@ -85,98 +123,181 @@ class DiffGeometryYou(Assembly): "alpha": 90, "beta": 90, "gamma": 90, - }, is_setting=True) - self._append(AdjustableFS, f'/photonics/home/gac-bernina/eco/configuration/crystals/{name}_u_matrix', name="u_matrix", default_value=[], is_setting=True, is_display=False) - self._append(AdjustableFS, f'/photonics/home/gac-bernina/eco/configuration/crystals/{name}_ub_matrix', name="ub_matrix", default_value=[], is_setting=True, is_display=False) - self._append(AdjustableFS, f'/photonics/home/gac-bernina/eco/configuration/crystals/{name}_orientations', name="orientations", default_value=[], is_setting=True) - self._append(AdjustableFS, f'/photonics/home/gac-bernina/eco/configuration/crystals/{name}_reflections', name="reflections", default_value=[], is_setting=True) + }, + is_setting=True, + ) + self._append( + AdjustableFS, + f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_u_matrix", + name="u_matrix", + default_value=[], + is_setting=True, + is_display=False, + ) + self._append( + AdjustableFS, + f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_ub_matrix", + name="ub_matrix", + default_value=[], + is_setting=True, + is_display=False, + ) + self._append( + AdjustableFS, + f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_orientations", + name="orientations", + default_value=[], + is_setting=True, + ) + self._append( + AdjustableFS, + f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_reflections", + name="reflections", + default_value=[], + is_setting=True, + ) self.diffractometer = diffractometer_you cons = { - 'mu': None, - 'eta': None, - 'chi': None, - 'phi': None, - 'delta': None, - 'nu': None, - 'a_eq_b': None, - 'bin_eq_bout': None, - 'betain': None, - 'betaout': None, - 'qaz': None, - 'naz': None, - 'alpha': None, - 'beta': None, - 'bisect': None, - 'psi': None, - 'omega': None, + "mu": None, + "eta": None, + "chi": None, + "phi": None, + "delta": None, + "nu": None, + "a_eq_b": None, + "bin_eq_bout": None, + "betain": None, + "betaout": None, + "qaz": None, + "naz": None, + "alpha": None, + "beta": None, + "bisect": None, + "psi": None, + "omega": None, } - self._append(AdjustableFS, f'/photonics/home/gac-bernina/eco/configuration/crystals/{name}_constraints', name="_constraints", default_value=cons, is_setting=True, is_display=False) - self._append(AdjustableObject, self._constraints, name="constraints", is_setting=False, is_display='recursive') - + self._append( + AdjustableFS, + f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_constraints", + name="_constraints", + default_value=cons, + is_setting=True, + is_display=False, + ) + self._append( + AdjustableObject, + self._constraints, + name="constraints", + is_setting=False, + is_display="recursive", + ) cfg = self.diffractometer.configuration - adjs = ['nu', 'mu', 'delta', 'eta', 'chi', 'phi'] - if 'kappa' in cfg: - adjs = ['nu', 'mu', 'delta', 'eta_kap', 'kappa', 'phi_kap'] - adj_keys = [adj if adj in self.diffractometer.__dict__.keys() else adj+'_manual' for adj in adjs] - self._diff_adjs = {adj: self.diffractometer.__dict__[adj_key] for adj, adj_key in zip(adjs, adj_keys)} - + adjs = ["nu", "mu", "delta", "eta", "chi", "phi"] + adjs = [] + if "base" in cfg: + adjs += ["mu"] + if "arm" in cfg: + adjs += ["nu", "delta"] + if "kappa" in cfg: + adjs += ["eta_kap", "kappa", "phi_kap"] + adj_keys = [ + adj if adj in self.diffractometer.__dict__.keys() else adj + "_manual" + for adj in adjs + ] + self._diff_adjs = { + adj: self.diffractometer.__dict__[adj_key] + for adj, adj_key in zip(adjs, adj_keys) + } def get_h(*args, **kwargs): return self.calc_hkl()[0] + def set_h(val): - return self._calc_angles_unique_diffractometer([val,None,None]) + return self._calc_angles_unique_diffractometer([val, None, None]) + def get_k(*args, **kwargs): return self.calc_hkl()[1] + def set_k(val): - return self._calc_angles_unique_diffractometer([None,val,None]) + return self._calc_angles_unique_diffractometer([None, val, None]) + def get_l(*args, **kwargs): return self.calc_hkl()[2] + def set_l(val): - return self._calc_angles_unique_diffractometer([None,None,val]) + return self._calc_angles_unique_diffractometer([None, None, val]) + def get_hkl(*args, **kwargs): return self.calc_hkl() + def set_hkl(val): return self._calc_angles_unique_diffractometer(val) - - self._append(AdjustableVirtual, list(self._diff_adjs.values()), get_h, set_h, name="h") - self._append(AdjustableVirtual, list(self._diff_adjs.values()), get_k, set_k, name="k") - self._append(AdjustableVirtual, list(self._diff_adjs.values()), get_l, set_l, name="l") - self._append(AdjustableVirtual, list(self._diff_adjs.values()), get_hkl, self._calc_angles_unique_diffractometer, name="hkl") + self._append( + AdjustableVirtual, list(self._diff_adjs.values()), get_h, set_h, name="h" + ) + self._append( + AdjustableVirtual, list(self._diff_adjs.values()), get_k, set_k, name="k" + ) + self._append( + AdjustableVirtual, list(self._diff_adjs.values()), get_l, set_l, name="l" + ) + self._append( + AdjustableVirtual, + list(self._diff_adjs.values()), + get_hkl, + self._calc_angles_unique_diffractometer, + name="hkl", + ) self.recalculate() def convert_from_you(self, **kwargs): cfg = self.diffractometer.configuration - if 'kappa' in cfg: - eta_kap, kappa, phi_kap = self.diffractometer.calc_you2kappa(kwargs["eta"],kwargs["chi"],kwargs["phi"]) + if "kappa" in cfg: + eta_kap, kappa, phi_kap = self.diffractometer.calc_you2kappa( + kwargs["eta"], kwargs["chi"], kwargs["phi"] + ) kwargs.update({"eta_kap": eta_kap, "kappa": kappa, "phi_kap": phi_kap}) return [kwargs[key] for key in self._diff_adjs.keys()] - def convert_to_you(self, nu=None, mu=None, delta=None, eta=None, chi=None, phi=None, eta_kap=None, kappa=None, phi_kap=None): + def convert_to_you( + self, + nu=None, + mu=None, + delta=None, + eta=None, + chi=None, + phi=None, + eta_kap=None, + kappa=None, + phi_kap=None, + ): cfg = self.diffractometer.configuration - if 'kappa' in cfg: + if "kappa" in cfg: eta, chi, phi = self.diffractometer.calc_kappa2you(eta_kap, kappa, phi_kap) return nu, mu, delta, eta, chi, phi def get_diffractometer_angles(self): ### assume that all angles exist in diffractometer at least as manual adjustable ### - nu, mu, delta, eta, chi, phi = self.convert_to_you(**{key: adj() for key, adj in self._diff_adjs.items()}) + nu, mu, delta, eta, chi, phi = self.convert_to_you( + **{key: adj() for key, adj in self._diff_adjs.items()} + ) return mu, delta, nu, eta, chi, phi - def _calc_angles_unique_diffractometer(self,hkl): + def _calc_angles_unique_diffractometer(self, hkl): angles = self.calc_angles_unique(*hkl) return self.convert_from_you(**angles) def check_target_value_within_limits(self, **kwargs): - ### virtual adjustables got a new function check_target_value_within_limits(values) + ### virtual adjustables got a new function check_target_value_within_limits(values) in_lims = [] target_values = self.convert_from_you(**kwargs) for val, adj in zip(target_values, self._diff_adjs.values()): - if hasattr(adj, 'get_limits'): + if hasattr(adj, "get_limits"): lim_low, lim_high = adj.get_limits() in_lims.append((lim_low < val) and (val < lim_high)) - else: + else: raise Exception(f"Failed to get limits of adjustable {adj.name}") return all(in_lims) @@ -190,14 +311,32 @@ class DiffGeometryYou(Assembly): alpha = float(input("Angle alpha (90): ") or 90) beta = float(input(f"Angle beta ({alpha}): ") or alpha) gamma = float(input(f"Angle gamma ({alpha}): ") or alpha) - im = Image.open('/photonics/home/gac-bernina/eco/configuration/crystals/you_diffractometer.png') - normal = [float(val) for val in input("(h,k,l) surface normal (along YOU z-axis), e.g. 0,0,1: ").split(",") or [0,0,1]] - inplane = [float(val) for val in input("(h,k,l) in-plane orientation along beam (YOU y-axis), e.g. 1,0,0: ").split(",") or [1,0,0]] + im = Image.open( + "/photonics/home/gac-bernina/eco/configuration/crystals/you_diffractometer.png" + ) + normal = [ + float(val) + for val in input( + "(h,k,l) surface normal (along YOU z-axis), e.g. 0,0,1: " + ).split(",") + or [0, 0, 1] + ] + inplane = [ + float(val) + for val in input( + "(h,k,l) in-plane orientation along beam (YOU y-axis), e.g. 1,0,0: " + ).split(",") + or [1, 0, 0] + ] self.set_unit_cell(crystal_name, a, b, c, alpha, beta, gamma) - self.add_orientation(normal, (0,0,1), tag='surface normal') - self.add_orientation(inplane, (0,1,0), tag='in-plane along x-ray beam direction') + self.add_orientation(normal, (0, 0, 1), tag="surface normal") + self.add_orientation( + inplane, (0, 1, 0), tag="in-plane along x-ray beam direction" + ) self.calc_ub() - print("UB was calculated - next please set the constraints (.constraints) and the limits of the diffractometer motors") + print( + "UB was calculated - next please set the constraints (.constraints) and the limits of the diffractometer motors" + ) def set_unit_cell( self, name_crystal, a=None, b=None, c=None, alpha=None, beta=None, gamma=None @@ -217,18 +356,30 @@ class DiffGeometryYou(Assembly): def recalculate(self): self.ubcalc = dccalc.UBCalculation("you") - #self.ubcalc.n_phi = [0,0,1] + # self.ubcalc.n_phi = [0,0,1] uc = self.unit_cell() self.ubcalc.set_lattice(uc.pop("name"), **uc) for ori in self.orientations(): self.ubcalc.add_orientation(ori.pop("hkl"), ori.pop("xyz"), **ori) for refl in self.reflections(): position = Position(*refl.pop("position")) - self.ubcalc.add_reflection(refl.pop("hkl"), position, refl.pop("energy")*1e-3, **refl) + self.ubcalc.add_reflection( + refl.pop("hkl"), position, refl.pop("energy") * 1e-3, **refl + ) self._u_ub_to_dc() - - def add_reflection(self, hkl, mu=None, delta=None, nu=None, eta=None, chi=None, phi=None, energy=None, tag=None,): + def add_reflection( + self, + hkl, + mu=None, + delta=None, + nu=None, + eta=None, + chi=None, + phi=None, + energy=None, + tag=None, + ): """Add a reference reflection. Adds a reflection position in degrees and in the systems internal @@ -247,7 +398,10 @@ class DiffGeometryYou(Assembly): """ setvals = [mu, delta, nu, eta, chi, phi] curvals = self.get_diffractometer_angles() - angs = [curval if setval == None else setval for setval, curval in zip(setvals, curvals)] + angs = [ + curval if setval == None else setval + for setval, curval in zip(setvals, curvals) + ] if energy is None: energy = self.get_energy() position = Position(*angs) @@ -272,7 +426,6 @@ class DiffGeometryYou(Assembly): print(f"Removed reflection {removed}") self.recalculate() - def add_orientation(self, hkl, xyz, position=None, tag=None): """Add a reference orientation. @@ -310,7 +463,6 @@ class DiffGeometryYou(Assembly): print(f"Removed reflection {removed}") self.recalculate() - def calc_ub(self, idx1=0, idx2=1): """Calculate UB matrix. @@ -333,10 +485,24 @@ class DiffGeometryYou(Assembly): self._u_ub_from_dc() def show_you_geometry(self): - im = Image.open('/photonics/home/gac-bernina/eco/configuration/crystals/you_diffractometer.png') + im = Image.open( + "/photonics/home/gac-bernina/eco/configuration/crystals/you_diffractometer.png" + ) im.show() - def refine_ub(self, hkl, mu=None, delta=None, nu=None, eta=None, chi=None, phi=None, energy=None, refine_lattice=False, refine_umatrix=False): + def refine_ub( + self, + hkl, + mu=None, + delta=None, + nu=None, + eta=None, + chi=None, + phi=None, + energy=None, + refine_lattice=False, + refine_umatrix=False, + ): """ Refine UB matrix to using single reflection. @@ -366,16 +532,24 @@ class DiffGeometryYou(Assembly): return setvals = [mu, delta, nu, eta, chi, phi] curvals = self.get_diffractometer_angles() - angs = [curval if setval == None else setval for setval, curval in zip(setvals, curvals)] + angs = [ + curval if setval == None else setval + for setval, curval in zip(setvals, curvals) + ] if energy is None: energy = self.get_energy() wl = self.en2lam(energy) position = Position(*angs) self.recalculate() - self.ubcalc.refine_ub(hkl, position=position, wavelength=wl, refine_lattice=refine_lattice, refine_umatrix=refine_umatrix) + self.ubcalc.refine_ub( + hkl, + position=position, + wavelength=wl, + refine_lattice=refine_lattice, + refine_umatrix=refine_umatrix, + ) self._u_ub_from_dc() - def fit_ub(self, indices=None, refine_lattice=False, refine_umatrix=True): """Refine UB matrix using reference reflections. @@ -396,63 +570,87 @@ class DiffGeometryYou(Assembly): self.recalculate() if indices is None: indices = list(range(len(self.reflections()))) - ub, lat = self.ubcalc.fit_ub(indices, refine_lattice=refine_lattice, refine_umatrix=refine_umatrix) + ub, lat = self.ubcalc.fit_ub( + indices, refine_lattice=refine_lattice, refine_umatrix=refine_umatrix + ) if refine_umatrix: print("\nFitted UB matrix applied") else: - print("\nFitted UB matrix not applied. To apply it, set refine_umatrix=True") + print( + "\nFitted UB matrix not applied. To apply it, set refine_umatrix=True" + ) print(ub) if refine_lattice: print("\nFitted lattice applied") else: print("\nFitted lattice not applied. To apply it, set refine_lattice=True") for k, val in { - "name": lat[0], - "a": lat[1], - "b": lat[2], - "c": lat[3], - "alpha": lat[4], - "beta": lat[5], - "gamma": lat[6], - }.items(): + "name": lat[0], + "a": lat[1], + "b": lat[2], + "c": lat[3], + "alpha": lat[4], + "beta": lat[5], + "gamma": lat[6], + }.items(): print(f"{k:8}: {val}") self._u_ub_from_dc() if refine_lattice: self._lat_from_dc() - def calc_angles(self, h=None,k=None,l=None, energy=None): - """calculate diffractometer angles for a given h,k,l and energy in eV. - If any of the h, k, l are not given, their current value is used instead. + def calc_angles(self, h=None, k=None, l=None, energy=None): + """calculate diffractometer angles for a given h,k,l and energy in eV. + If any of the h, k, l are not given, their current value is used instead. energy: float energy of the x-ray beam, if not given, the mono or machine energy are used depending on the beamline mode Shows all solutions neglecting diffractometer limits""" - setvals = [h,k,l] - curvals = [self.h, self.k, self.l] - h,k,l = [curval() if setval == None else setval for setval, curval in zip(setvals, curvals)] + setvals = [h, k, l] + curvals = [self.h, self.k, self.l] + h, k, l = [ + curval() if setval == None else setval + for setval, curval in zip(setvals, curvals) + ] self.recalculate() cons = Constraints(self._constraints()) hklcalc = HklCalculation(self.ubcalc, cons) if energy is None: energy = self.get_energy() lam = self.en2lam(energy) - result = hklcalc.get_position(h,k,l,lam) - result = pd.concat([pd.DataFrame.from_dict({**tres[0].asdict,**tres[1]},orient='index', columns=[f'sol. {n}']) for n,tres in enumerate(result)],axis=1) + result = hklcalc.get_position(h, k, l, lam) + result = pd.concat( + [ + pd.DataFrame.from_dict( + {**tres[0].asdict, **tres[1]}, orient="index", columns=[f"sol. {n}"] + ) + for n, tres in enumerate(result) + ], + axis=1, + ) return result.T - def calc_angles_unique(self, h=None,k=None,l=None, energy=None): - """calculate unique solution of diffractometer angles for a given h,k,l and energy in eV. - If any of the h, k, l are not given, their current value is used instead. + def calc_angles_unique(self, h=None, k=None, l=None, energy=None): + """calculate unique solution of diffractometer angles for a given h,k,l and energy in eV. + If any of the h, k, l are not given, their current value is used instead. If the energy is not given, the monochromator energy is used.""" - df = self.calc_angles(h,k,l,energy) - in_lims = np.array([self.check_target_value_within_limits(**df.loc[idx].to_dict()) for idx in df.index]) + df = self.calc_angles(h, k, l, energy) + in_lims = np.array( + [ + self.check_target_value_within_limits(**df.loc[idx].to_dict()) + for idx in df.index + ] + ) idx_in = df.index[in_lims] idx_out = df.index[~in_lims] if len(idx_in) > 1: - print(f"There is not a unique angular configuration to reach ({h},{k},{l}), please change the diffractometer motor soft limits to allow only one of the solutions shown below:") + print( + f"There is not a unique angular configuration to reach ({h},{k},{l}), please change the diffractometer motor soft limits to allow only one of the solutions shown below:" + ) print(df.loc[idx_in]) raise Exception("No unique solution") - elif len(idx_in) ==0: - print("There is no angular configuration, which is allowed for the current diffractometer motor soft limits. please check the diffractometer limits.") + elif len(idx_in) == 0: + print( + "There is no angular configuration, which is allowed for the current diffractometer motor soft limits. please check the diffractometer limits." + ) print("Solutions") print(df) raise Exception("No unique solution") @@ -460,14 +658,18 @@ class DiffGeometryYou(Assembly): return solution_unique.to_dict() - - def calc_hkl(self, mu=None, delta=None, nu=None, eta=None, chi=None, phi=None, energy=None): - """calculate (h,k,l) for given diffractometer angles and energy in eV. - If any of the diffractometer angles are not given, their current value is used instead. + def calc_hkl( + self, mu=None, delta=None, nu=None, eta=None, chi=None, phi=None, energy=None + ): + """calculate (h,k,l) for given diffractometer angles and energy in eV. + If any of the diffractometer angles are not given, their current value is used instead. If the energy is not given, the monochromator energy is used""" setvals = [mu, delta, nu, eta, chi, phi] curvals = self.get_diffractometer_angles() - angs = [curval if setval == None else setval for setval, curval in zip(setvals, curvals)] + angs = [ + curval if setval == None else setval + for setval, curval in zip(setvals, curvals) + ] pos = Position(*angs) self.recalculate() if energy is None: @@ -486,13 +688,12 @@ class DiffGeometryYou(Assembly): energy = PV("SAROP21-ARAMIS:ENERGY").value return energy - def _u_ub_from_dc(self): self.ub_matrix(self.ubcalc.UB.tolist()) self.u_matrix(self.ubcalc.U.tolist()) def _u_ub_to_dc(self): - if len(self.ub_matrix())>0: + if len(self.ub_matrix()) > 0: self.ubcalc.set_ub(self.ub_matrix()) self.ubcalc.set_u(self.u_matrix()) @@ -501,11 +702,11 @@ class DiffGeometryYou(Assembly): def en2lam(self, en): """input: energy in eV, returns wavelength in A""" - return 12398.419843320025/en + return 12398.419843320025 / en def lam2en(self, lam): """input: wavelength in A, returns energy in eV""" - return 12398.419843320025/lam + return 12398.419843320025 / lam pass # def __init__(sel): diff --git a/eco/xdiagnostics/profile_monitors.py b/eco/xdiagnostics/profile_monitors.py index 22f3003..c9e1def 100755 --- a/eco/xdiagnostics/profile_monitors.py +++ b/eco/xdiagnostics/profile_monitors.py @@ -148,6 +148,8 @@ class ProfKbBernina(Assembly): self._append( MotorRecord, pvname_zoom, name="zoom", is_setting=True, is_display=True ) + ix = self.settings_collection._list.index(self.zoom.offset) + self.settings_collection._list.pop(ix) def movein_keep_target(self, wait=False): ch = self.mirror_in.set_target_value(1) diff --git a/eco/xoptics/reflaser.py b/eco/xoptics/reflaser.py index c92e48f..7c1f8c5 100644 --- a/eco/xoptics/reflaser.py +++ b/eco/xoptics/reflaser.py @@ -35,7 +35,7 @@ class RefLaser_Aramis(Assembly): ) self._append( RefLaserAperture, - "SAROP21-OLIR136", + "SAROP21-OLIR134", name="aperture", is_setting=True, is_display="recursive", From 8df2a7c1e4b4203c96c4604d87376390ca10679d Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Wed, 25 Jan 2023 21:52:12 +0100 Subject: [PATCH 27/52] added status free quick scan options --- eco/acquisition/daq_client.py | 4 ++ eco/acquisition/scan.py | 18 +++++- eco/bernina/bernina.py | 101 ++++++++++++++++++++++---------- eco/bernina/config.py | 22 ------- eco/dummy/bernina.py | 8 +++ eco/timing/lasertiming_edwin.py | 7 +++ eco/timing/timing_diag.py | 31 ++++++++++ eco/xoptics/dcm_new.py | 8 +++ eco/xoptics/kb_bernina.py | 17 +++++- 9 files changed, 159 insertions(+), 57 deletions(-) diff --git a/eco/acquisition/daq_client.py b/eco/acquisition/daq_client.py index 1766eb5..200d842 100644 --- a/eco/acquisition/daq_client.py +++ b/eco/acquisition/daq_client.py @@ -2,6 +2,7 @@ import requests from pathlib import Path from time import sleep from ..epics.detector import DetectorPvDataStream +from epics import PV from ..acquisition.utilities import Acquisition from ..elements.assembly import Assembly from ..utilities.path_alias import PathAlias @@ -47,6 +48,7 @@ class Daq(Assembly): self.pgroup = pgroup if type(pulse_id_adj) is str: self.pulse_id = DetectorPvDataStream(pulse_id_adj, name="pulse_id") + self._pid_wo_automonitor = PV("SGE-CPCW-85-EVR0:RX-PULSEID", connection_timeout=0.05, auto_monitor=False) else: self.pulse_id = pulse_id_adj self.running = [] @@ -91,6 +93,8 @@ class Daq(Assembly): def start(self, label=None, **kwargs): start_id = self.pulse_id.get_current_value() + print(f"PID stream : {start_id}") + print(f"PID wo automonitor: {self._pid_wo_automonitor.get()}") acq_pars = { "label": label, "start_id": start_id, diff --git a/eco/acquisition/scan.py b/eco/acquisition/scan.py index 230ba17..2110b30 100755 --- a/eco/acquisition/scan.py +++ b/eco/acquisition/scan.py @@ -62,6 +62,7 @@ class Scan: run_table=None, run_number=None, elog=None, + **kwargs_callbacks, ): if np.any([char in fina for char in inval_chars]): raise ScanNameError @@ -105,6 +106,7 @@ class Scan: self.run_number = run_number self.remaining_tasks = [] self.callbacks_end_scan = callbacks_end_scan + self.callbacks_kwargs = kwargs_callbacks print(f"Scan info in file {self.scan_info_filename}.") for adj in self.adjustables: tv = adj.get_current_value() @@ -113,7 +115,7 @@ class Scan: if callbacks_start_scan: for caller in callbacks_start_scan: - caller(self) + caller(self, **self.callbacks_kwargs) def get_filename(self, stepNo, Ndigits=4): fina = os.path.join(self.basepath, Path(self.fina).stem) @@ -266,7 +268,7 @@ class Scan: if self.callbacks_end_scan: for caller in self.callbacks_end_scan: - caller(self) + caller(self, **self.callbacks_kwargs) if self.return_at_end == "question": if input("Change back to initial values? (y/n)")[0] == "y": chs = self.changeToInitialValues() @@ -349,6 +351,7 @@ class Scans: start_immediately=True, step_info=None, return_at_end="question", + **kwargs_callbacks, ): positions0 = np.linspace(start0_pos, end0_pos, N_intervals + 1) positions1 = np.linspace(start1_pos, end1_pos, N_intervals + 1) @@ -370,6 +373,7 @@ class Scans: run_table=self._run_table, elog=self._elog, return_at_end=return_at_end, + **kwargs_callbacks, ) if start_immediately: s.scanAll(step_info=step_info) @@ -385,6 +389,7 @@ class Scans: settling_time=0, step_info=None, return_at_end=True, + **kwargs_callbacks, ): adjustable = DummyAdjustable() @@ -412,6 +417,7 @@ class Scans: elog=self._elog, run_number=run_number, return_at_end=return_at_end, + **kwargs_callbacks, ) if start_immediately: s.scanAll(step_info=step_info) @@ -430,6 +436,7 @@ class Scans: step_info=None, return_at_end="question", settling_time=0, + **kwargs_callbacks, ): positions = np.linspace(start_pos, end_pos, N_intervals + 1) values = [[tp] for tp in positions] @@ -454,6 +461,7 @@ class Scans: run_table=self._run_table, elog=self._elog, run_number=run_number, + **kwargs_callbacks, ) if start_immediately: s.scanAll(step_info=step_info) @@ -472,6 +480,7 @@ class Scans: settling_time=0, step_info=None, return_at_end="question", + **kwargs_callbacks, ): positions = np.linspace(start_pos, end_pos, N_intervals + 1) current = adjustable.get_current_value() @@ -497,6 +506,7 @@ class Scans: run_table=self._run_table, elog=self._elog, run_number=run_number, + **kwargs_callbacks, ) if start_immediately: s.scanAll(step_info=step_info) @@ -519,6 +529,7 @@ class Scans: settling_time=0, step_info=None, return_at_end="question", + **kwargs_callbacks, ): positions = posList values = [[tp] for tp in positions] @@ -543,6 +554,7 @@ class Scans: run_table=self._run_table, elog=self._elog, run_number=run_number, + **kwargs_callbacks, ) if start_immediately: s.scanAll(step_info=step_info) @@ -563,6 +575,7 @@ class Scans: start_immediately=True, step_info=None, return_at_end="question", + **kwargs_callbacks, ): positions0 = np.linspace(start0_pos, end0_pos, N_intervals + 1) positions1 = np.linspace(start1_pos, end1_pos, N_intervals + 1) @@ -589,6 +602,7 @@ class Scans: callbacks_end_scan=self.callbacks_end_scan, run_table=self._run_table, elog=self._elog, + **kwargs_callbacks, ) if start_immediately: s.scanAll(step_info=step_info) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 0167042..814f67b 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -835,20 +835,38 @@ namespace.append_obj( ) -def _wait_for_tasks(scan): +namespace.append_obj( + "Epicstools", + name="epics_daq", + module_name="eco.acquisition.epics_data", + channel_list=channels_CA_epicsdaq, + default_file_path=f"/sf/bernina/data/{config_bernina.pgroup}/res/epics_daq/", + lazy=True, +) + + +def _wait_for_tasks(scan, **kwargs): print("checking remaining tasks from previous scan ...") for task in scan.remaining_tasks: task.join() print("... done.") -def _append_namesace_status_to_scan(scan, daq=daq, namespace=namespace): +def _append_namesace_status_to_scan( + scan, daq=daq, namespace=namespace, append_status_info=True, **kwargs +): + if not append_status_info: + return namespace_status = namespace.get_status(base=None) stat = {"status_run_start": namespace_status} scan.status = stat -def _write_namespace_status_to_scan(scan, daq=daq, namespace=namespace): +def _write_namespace_status_to_scan( + scan, daq=daq, namespace=namespace, append_status_info=True, **kwargs +): + if not append_status_info: + return namespace_status = namespace.get_status(base=None) scan.status["status_run_end"] = namespace_status runno = daq.get_last_run_number() @@ -875,7 +893,7 @@ def _write_namespace_status_to_scan(scan, daq=daq, namespace=namespace): scan.scan_info["scan_parameters"]["status"] = "aux/status.json" -def _write_namespace_aliases_to_scan(scan, daq=daq): +def _write_namespace_aliases_to_scan(scan, daq=daq, **kwargs): namespace_aliases = namespace.alias.get_all() runno = daq.get_last_run_number() pgroup = daq.pgroup @@ -901,7 +919,7 @@ def _write_namespace_aliases_to_scan(scan, daq=daq): scan.scan_info["scan_parameters"]["aliases"] = "aux/aliases.json" -def _message_end_scan(scan): +def _message_end_scan(scan, **kwargs): print(f"Finished run {scan.run_number}.") e = pyttsx3.init() e.say(f"Finished run {scan.run_number}.") @@ -919,7 +937,7 @@ def _message_end_scan(scan): # print(f"Status: {response.json()['status']} Message: {response.json()['message']}") -def _create_general_run_info(scan, daq=daq): +def _create_general_run_info(scan, daq=daq, **kwargs): with open(scan.scan_info_filename, "r") as f: si = json.load(f) @@ -932,7 +950,7 @@ def _create_general_run_info(scan, daq=daq): info["steps"] = [] -def _copy_scan_info_to_raw(scan, daq=daq): +def _copy_scan_info_to_raw(scan, daq=daq, **kwargs): scan.writeScanInfo() @@ -975,7 +993,9 @@ def _copy_scan_info_to_raw(scan, daq=daq): from eco.detector import Jungfrau -def _copy_selected_JF_pedestals_to_raw(scan, daq=daq): +def _copy_selected_JF_pedestals_to_raw( + scan, daq=daq, copy_selected_JF_pedestals_to_raw=True, **kwargs +): def copy_to_aux(daq): runno = daq.get_last_run_number() pgroup = daq.pgroup @@ -1006,11 +1026,12 @@ def _copy_selected_JF_pedestals_to_raw(scan, daq=daq): f"Status: {response.json()['status']} Message: {response.json()['message']}" ) - scan.remaining_tasks.append(Thread(target=copy_to_aux, args=[daq])) - scan.remaining_tasks[-1].start() + if copy_selected_JF_pedestals_to_raw: + scan.remaining_tasks.append(Thread(target=copy_to_aux, args=[daq])) + scan.remaining_tasks[-1].start() -def _increment_daq_run_number(scan, daq=daq): +def _increment_daq_run_number(scan, daq=daq, **kwargs): try: daq_last_run_number = daq.get_last_run_number() if int(scan.run_number) is int(daq_last_run_number) + 1: @@ -1062,7 +1083,7 @@ class Monitor: import traceback -def append_scan_monitors(scan, daq=daq): +def append_scan_monitors(scan, daq=daq, **kwargs): scan.monitors = {} for adj in scan.adjustables: try: @@ -1094,7 +1115,7 @@ def append_scan_monitors(scan, daq=daq): traceback.print_exc() -def end_scan_monitors(scan, daq=daq): +def end_scan_monitors(scan, daq=daq, **kwargs): for tmon in scan.monitors: scan.monitors[tmon].stop_callback() @@ -1128,8 +1149,14 @@ def end_scan_monitors(scan, daq=daq): # scan.monitors = None +def _init_all(scan, append_status_info=True, **kwargs): + if not append_status_info: + return + namespace.init_all(silent=False) + + callbacks_start_scan = [] -callbacks_start_scan = [lambda scan: namespace.init_all(silent=False)] +callbacks_start_scan.append(_init_all) callbacks_start_scan.append(_wait_for_tasks) callbacks_start_scan.append(_append_namesace_status_to_scan) callbacks_start_scan.append(_increment_daq_run_number) @@ -1147,7 +1174,11 @@ callbacks_end_scan.append(_message_end_scan) # if self._run_table or self._elog: -def _create_metadata_structure_start_scan(scan, run_table=run_table, elog=elog): +def _create_metadata_structure_start_scan( + scan, run_table=run_table, elog=elog, append_status_info=True, **kwargs +): + if not append_status_info: + return runname = os.path.basename(scan.fina).split(".")[0] runno = int(runname.split("run")[1].split("_")[0]) metadata = { @@ -1266,23 +1297,23 @@ namespace.append_obj( module_name="eco.devices_general.cameras_ptz", ) -namespace.append_obj( - "BerninaInlineMicroscope", - pvname_camera="SARES20-CAMS142-M3", - lazy=True, - name="samplecam_inline", - module_name="eco.microscopes", -) - # namespace.append_obj( -# "MicroscopeMotorRecord", -# pvname_camera="SARES20-CAMS142-C1", -# lazy=True, -# name="samplecam", -# module_name="eco.microscopes", -# pvname_zoom="SARES20-MF1:MOT_16", +# "BerninaInlineMicroscope", +# pvname_camera="SARES20-CAMS142-M3", +# lazy=True, +# name="samplecam_inline", +# module_name="eco.microscopes", # ) +namespace.append_obj( + "MicroscopeMotorRecord", + pvname_camera="SARES20-CAMS142-C1", + lazy=True, + name="samplecam", + module_name="eco.microscopes", + pvname_zoom="SARES20-MF1:MOT_16", +) + # namespace.append_obj( # "MicroscopeMotorRecord", # "SARES20-CAMS142-C1", @@ -1293,9 +1324,17 @@ namespace.append_obj( # ) +# namespace.append_obj( +# "CameraBasler", +# "SARES20-CAMS142-M2", +# lazy=True, +# name="samplecam_sideview", +# module_name="eco.devices_general.cameras_swissfel", +# ) + namespace.append_obj( "CameraBasler", - "SARES20-CAMS142-M2", + "SARES20-CAMS142-C3", lazy=True, name="samplecam_sideview", module_name="eco.devices_general.cameras_swissfel", @@ -1305,7 +1344,7 @@ namespace.append_obj( "CameraBasler", "SARES20-CAMS142-C2", lazy=True, - name="samplecam_sideview_45deg", + name="samplecam_sideview_45deg_THC", module_name="eco.devices_general.cameras_swissfel", ) diff --git a/eco/bernina/config.py b/eco/bernina/config.py index a4884d0..211801e 100755 --- a/eco/bernina/config.py +++ b/eco/bernina/config.py @@ -412,28 +412,6 @@ components = [ "type": "eco.loptics.laser_shutter:laser_shutter", "kwargs": {}, }, - { - "args": [], - "name": "epics_channel_list", - "desc": "epics channel list", - "type": "eco.utilities.config:ChannelList", - "kwargs": { - "file_name": "/sf/bernina/config/channel_lists/default_channel_list_epics" - }, - "lazy": True, - }, - { - "args": [], - "name": "epics_daq", - "z_und": 142, - "desc": "epics data acquisition", - "type": "eco.acquisition.epics_data:Epicstools", - "kwargs": { - "channel_list": Component("epics_channel_list"), - "default_file_path": f"/sf/bernina/data/{config['pgroup']}/res/epics_daq/", - }, - "lazy": True, - }, # { # "args": [], # "name": "daq_dia_old", diff --git a/eco/dummy/bernina.py b/eco/dummy/bernina.py index 98ae666..02dc2d0 100644 --- a/eco/dummy/bernina.py +++ b/eco/dummy/bernina.py @@ -456,6 +456,14 @@ namespace.append_obj( name="xrd", lazy=True, ) + +namespace.append_obj( + "HexapodSymmetrie", + name="usd_table", + module_name="eco.endstations.hexapod", + offset=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0], +) + namespace.append_obj( "KBMirrorBernina_new", "SAROP21-OKBV139", diff --git a/eco/timing/lasertiming_edwin.py b/eco/timing/lasertiming_edwin.py index a8a2224..6ac7098 100644 --- a/eco/timing/lasertiming_edwin.py +++ b/eco/timing/lasertiming_edwin.py @@ -272,6 +272,13 @@ class XltEpics(Assembly): is_setting=True, is_display=True, ) + self._append( + AdjustablePv, + self.pvname + ":LONG_DELAY_THRESH", + name="long_delay_threshold", + is_setting=True, + is_display=True, + ) # self._append( # DetectorPvData, # "SLAAR-LGEN:DLY_OFFS2", diff --git a/eco/timing/timing_diag.py b/eco/timing/timing_diag.py index 88c2365..c055867 100644 --- a/eco/timing/timing_diag.py +++ b/eco/timing/timing_diag.py @@ -128,6 +128,37 @@ class TimetoolBerninaUSD(Assembly): accuracy=10, is_setting=True, ) + + # SARES20-CAMS142-M5.bsen_signal_x_profile + # SARES20-CAMS142-M5.processing_parameters + # SARES20-CAMS142-M5.psen_signal_x_profile + # + # + + self._append( + DetectorBsStream, + "SARES20-CAMS142-M5.roi_signal_x_profile", + cachannel=None, + name="spectrum_signal", + is_setting=False, + is_display=True, + ) + self._append( + DetectorBsStream, + "SARES20-CAMS142-M5.roi_background_x_prof", + cachannel=None, + name="spectrum_background", + is_setting=False, + is_display=True, + ) + self._append( + DetectorBsStream, + "SARES20-CAMS142-M5.bsen_signal_x_profilef", + cachannel=None, + name="spectrum_bsen", + is_setting=False, + is_display=True, + ) self._append( DetectorBsStream, "SAROP21-ATT01:arrival_time", diff --git a/eco/xoptics/dcm_new.py b/eco/xoptics/dcm_new.py index be34b99..a4410a2 100644 --- a/eco/xoptics/dcm_new.py +++ b/eco/xoptics/dcm_new.py @@ -1,5 +1,6 @@ from ..devices_general.motors import MotorRecord, MotorRecord_new from ..epics.adjustable import AdjustablePv, AdjustablePvEnum +from ..epics.detector import DetectorPvData from epics import PV from ..devices_general.utilities import Changer from time import sleep @@ -77,6 +78,13 @@ class DoubleCrystalMono(Assembly): accuracy=0.5, name="energy", ) + self._append( + DetectorPvData, + energy_rb, + name="readback", + is_setting=False, + is_display=False, + ) self.settings_collection.append(self) def set_target_value(self, *args, **kwargs): diff --git a/eco/xoptics/kb_bernina.py b/eco/xoptics/kb_bernina.py index 53ab721..9d25bc4 100644 --- a/eco/xoptics/kb_bernina.py +++ b/eco/xoptics/kb_bernina.py @@ -37,6 +37,9 @@ class KBMirrorBernina(Assembly): self._append( KbHor, pvname_hor, name="hor", is_setting=True, is_display="recursive" ) + self._append( + AdjustablePvEnum, "SAROP21-OKB:MODE_SP", name="mode", is_setting=False + ) self.diffractometer = diffractometer self.usd_table = usd_table @@ -70,8 +73,11 @@ class KBMirrorBernina(Assembly): ) return pos_calc - def calc_fwhm(self, fwhm_hor, fwhm_ver, z_focver=0, z_fochor=0, E_phot=None): - """E_phot in eV, length units in mm.""" + def calc_fwhm( + self, fwhm_hor, fwhm_ver, z_focver=0, z_fochor=0, distances={}, E_phot=None + ): + """calculates beamsize at different locations based on the Beam size before kb focusing. + E_phot in eV, length units in mm.""" lam = constants.c * constants.h / constants.electron_volt / E_phot print(lam * 1e10) fwhm_fac = 1 / np.sqrt(2 * np.log(2)) # w = fwhm_fac*fwhm @@ -109,6 +115,13 @@ class KBMirrorBernina(Assembly): res["sample"] = (fwhm_z(z_fochor, w0_hor), fwhm_z(z_focver, w0_ver)) # res['fwhm_kbver'] = (fwhm_z(self.d_kbver+z_fochor,w0_hor),fwhm_z(self.d_kbver+z_focver,w0_ver)) # res['fwhm_kbhor'] = (fwhm_z(self.d_kbhor+z_fochor,w0_hor),fwhm_z(self.d_kbhor+z_focver,w0_ver)) + + for tdn, tdv in distances.items(): + res[tdn] = ( + fwhm_z(tdv + z_fochor, w0_hor), + fwhm_z(tdv + z_focver, w0_ver), + ) + return res def move_hex_for_kb_angles(self, the_kbver, the_kbhor): From 7436f8be5bab60e33480bae46c020d29e8e8e9be Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Fri, 10 Feb 2023 22:36:55 +0100 Subject: [PATCH 28/52] fixes --- eco/acquisition/daq_client.py | 2 - eco/bernina/bernina.py | 185 +++++++++++++++++---- eco/bernina/config.py | 30 ++-- eco/detector/jungfrau.py | 6 + eco/devices_general/motors.py | 8 +- eco/dummy/config.py | 25 +-- eco/elements/adjustable.py | 6 +- eco/fel/swissfel.py | 34 ++-- eco/loptics/bernina_laser.py | 49 ++++-- eco/timing/lasertiming_edwin.py | 32 +++- eco/utilities/elog.py | 3 + eco/utilities/runtable.py | 2 + eco/xoptics/dcm_new.py | 52 +++++- eco/xoptics/dcm_pathlength_compensation.py | 8 +- 14 files changed, 334 insertions(+), 108 deletions(-) diff --git a/eco/acquisition/daq_client.py b/eco/acquisition/daq_client.py index 200d842..377cf02 100644 --- a/eco/acquisition/daq_client.py +++ b/eco/acquisition/daq_client.py @@ -93,8 +93,6 @@ class Daq(Assembly): def start(self, label=None, **kwargs): start_id = self.pulse_id.get_current_value() - print(f"PID stream : {start_id}") - print(f"PID wo automonitor: {self._pid_wo_automonitor.get()}") acq_pars = { "label": label, "start_id": start_id, diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 814f67b..56e7288 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -835,14 +835,14 @@ namespace.append_obj( ) -namespace.append_obj( - "Epicstools", - name="epics_daq", - module_name="eco.acquisition.epics_data", - channel_list=channels_CA_epicsdaq, - default_file_path=f"/sf/bernina/data/{config_bernina.pgroup}/res/epics_daq/", - lazy=True, -) +# namespace.append_obj( +# "Epicstools", +# name="epics_daq", +# module_name="eco.acquisition.epics_data", +# channel_list=channels_CA_epicsdaq, +# default_file_path=f"/sf/bernina/data/{config_bernina.pgroup}/res/epics_daq/", +# lazy=True, +# ) def _wait_for_tasks(scan, **kwargs): @@ -1177,8 +1177,6 @@ callbacks_end_scan.append(_message_end_scan) def _create_metadata_structure_start_scan( scan, run_table=run_table, elog=elog, append_status_info=True, **kwargs ): - if not append_status_info: - return runname = os.path.basename(scan.fina).split(".")[0] runno = int(runname.split("run")[1].split("_")[0]) metadata = { @@ -1231,6 +1229,8 @@ def _create_metadata_structure_start_scan( metadata.update({"elog_post_link": scan._elog._log._url + str(scan._elog_id)}) except: print("elog posting failed") + if not append_status_info: + return try: run_table.append_run(runno, metadata=metadata) except: @@ -1311,7 +1311,7 @@ namespace.append_obj( lazy=True, name="samplecam", module_name="eco.microscopes", - pvname_zoom="SARES20-MF1:MOT_16", + pvname_zoom="SARES20-MF1:MOT_5", ) # namespace.append_obj( @@ -1510,27 +1510,27 @@ class N2jet(Assembly): class Incoupling(Assembly): def __init__(self, name=None): super().__init__(name=name) - self._append(SmaractRecord, "SARES23:ESB16", name="pitch", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB3", name="roll", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB10", name="pitch", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB13", name="roll", is_setting=True) # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) # self._append(SmaractRecord, "SARES23:ESB17", name="rotation", is_setting=True) -# namespace.append_obj( -# Incoupling, -# lazy=True, -# name="las_inc", -# ) - namespace.append_obj( - "High_field_thz_chamber", - name="thc", + Incoupling, lazy=True, - module_name="eco.endstations.bernina_sample_environments", - configuration=["ottifant"], + name="las_inc", ) +# namespace.append_obj( +# "High_field_thz_chamber", +# name="thc", +# lazy=True, +# module_name="eco.endstations.bernina_sample_environments", +# configuration=["ottifant"], +# ) + # class THz_in_air(Assembly): # def __init__(self, name=None): @@ -1674,6 +1674,29 @@ class JohannAnalyzer(Assembly): namespace.append_obj(JohannAnalyzer, name="analyzer") + +class GratingHolder(Assembly): + def __init__(self, name=""): + super().__init__(name=name) + self._append( + MotorRecord, + "SARES20-MF1:MOT_7", + name="vertical", + is_setting=True, + is_display=True, + ) + self._append( + SmaractRecord, + "SARES23:ESB6", + name="horizontal", + is_setting=True, + is_display=True, + ) + + +namespace.append_obj(GratingHolder, name="grating_holder") + + # ad hoc 2 pulse setup # class Laser2pulse(Assembly): # def __init__(self, name=None): @@ -1725,17 +1748,58 @@ namespace.append_obj(JohannAnalyzer, name="analyzer") # from eco.xoptics import dcm_pathlength_compensation as dpc -# namespace.append_obj( -# "MonoTimecompensation", -# # laser2pulse.pump_delay_exp, -# las.delay_glob, -# mono, -# "/sf/bernina/config/eco/reference_values/dcm_reference_timing.json", -# "/sf/bernina/config/eco/reference_values/dcm_reference_invert_delay.json", -# lazy=True, -# name="mono_time_corrected", -# module_name="eco.xoptics.dcm_pathlength_compensation", + +# namespace._append( +# "MotorRecord", +# "SLAAR21-LMOT-M523:MOTOR_1", +# name="delaystage_glob", +# is_setting=True, +# module_name="eco.devices_general.motors", # ) +# namespace.append( +# "DelayTime", +# delaystage_glob, +# name="delay_glob", +# is_setting=True, +# module_name="eco.loptics.bernina_laser", +# ) + + +delaystage_glob = MotorRecord( + "SLAAR21-LMOT-M523:MOTOR_1", + name="delaystage_glob", +) + +delay_glob = DelayTime( + delaystage_glob, + name="delay_glob", +) + +namespace.append_obj( + "SwissFel", + name="fel", + lazy=True, + module_name="eco.fel.swissfel", +) +namespace.append_obj( + "DoubleCrystalMono", + pvname="SAROP21-ODCM098", + fel=fel, + undulator_deadband_eV=2.0, + name="mono", + lazy=True, + module_name="eco.xoptics.dcm_new", +) +namespace.append_obj( + "MonoTimecompensation", + delay_glob, + mono.mono_und_energy, + "/sf/bernina/config/eco/reference_values/dcm_reference_timing.json", + "/sf/bernina/config/eco/reference_values/dcm_reference_invert_delay.json", + lazy=True, + name="mono_time_corrected", + module_name="eco.xoptics.dcm_pathlength_compensation", +) # ad hoc interferometric timetool @@ -1878,6 +1942,58 @@ from eco.devices_general.digitizers import DigitizerIoxosBoxcarChannel from eco.elements.adjustable import AdjustableVirtual import numpy as np + +class LiquidJetSpectroscopy(Assembly): + def __init__(self, name=None): + super().__init__(name=name) + self._append( + MotorRecord, + "SARES20-MF1:MOT_2", + name="x_jet", + backlash_definition=True, + is_setting=True, + ) + self._append( + MotorRecord, + "SARES20-MF1:MOT_4", + name="y_jet", + backlash_definition=True, + is_setting=True, + ) + self._append( + MotorRecord, + "SARES20-MF1:MOT_6", + name="z_jet", + backlash_definition=True, + is_setting=True, + ) + self._append( + MotorRecord, + "SARES20-MF1:MOT_3", + name="x_analyzer", + backlash_definition=True, + is_setting=True, + ) + self._append( + MotorRecord, + "SARES21-XRD:MOT_P_T", + name="y_vhdet", + is_setting=True, + ) + self._append( + Jungfrau, "JF03T01V02", name="det_i0", pgroup_adj=config_bernina.pgroup + ) + self._append( + Jungfrau, "JF04T01V01", name="det_em", pgroup_adj=config_bernina.pgroup + ) + self._append( + Jungfrau, "JF14T01V01", name="det_vhamos", pgroup_adj=config_bernina.pgroup + ) + + +namespace.append_obj(LiquidJetSpectroscopy, name="jet", lazy=True) + + # class Tapedrive(Assembly): # def __init__(self, name=None): # super().__init__(name=name) @@ -1886,8 +2002,7 @@ import numpy as np # ) # self._append(SmaractRecord, "SARES23:ESB18", name="freespace_pitch") # self._append(SmaractRecord, "SARES23:ESB13", name="freespace_roll") -# self._append(MotorRecord, "SARES20-MF1:MOT_7", name="rot_analyzer_hor") -# self._append(MotorRecord, "SARES20-MF1:MOT_8", name="rot_analyzer_ver") + # self._append(AnalogOutput, "SARES20-CWAG-GPS01:DAC01", name="shutter1") # self._append(AnalogOutput, "SARES20-CWAG-GPS01:DAC02", name="shutter2") diff --git a/eco/bernina/config.py b/eco/bernina/config.py index 211801e..e61e201 100755 --- a/eco/bernina/config.py +++ b/eco/bernina/config.py @@ -46,13 +46,21 @@ components = [ "args": [], "kwargs": {"screenshot_directory": "/sf/bernina/config/screenshots"}, }, - { - "name": "fel", - "type": "eco.fel.swissfel:SwissFel", - "args": [], - "kwargs": {}, - "desc": "Fel related control and feedback", - }, +# { +# "name": "fel", +# "type": "eco.fel.swissfel:SwissFel", +# "args": [], +# "kwargs": {}, +# "desc": "Fel related control and feedback", +# }, +# { +# "name": "mono", +# "args": ["SAROP21-ODCM098"], +# "kwargs": {}, +# "z_und": 98, +# "desc": "DCM Monochromator", +# "type": "eco.xoptics.dcm_new:DoubleCrystalMono", +# }, # { # "name": "slit_und", # "type": "eco.xoptics.slits:SlitFourBlades_old", @@ -186,14 +194,6 @@ components = [ "type": "eco.xoptics.offsetMirrors_new:OffsetMirrorsBernina", "kwargs": {}, }, - { - "name": "mono", - "args": ["SAROP21-ODCM098"], - "kwargs": {}, - "z_und": 98, - "desc": "DCM Monochromator", - "type": "eco.xoptics.dcm_new:DoubleCrystalMono", - }, { "name": "mono_old", "args": ["SAROP21-ODCM098"], diff --git a/eco/detector/jungfrau.py b/eco/detector/jungfrau.py index 261bcdc..0cd47fb 100644 --- a/eco/detector/jungfrau.py +++ b/eco/detector/jungfrau.py @@ -9,6 +9,7 @@ from ..aliases import Alias from pathlib import Path from ..elements import memory from datetime import datetime +import requests class Jungfrau(Assembly): @@ -152,6 +153,11 @@ class Jungfrau(Assembly): ) return is_available + def get_vis_url(self): + tmp = requests.get(f"{self.broker_address}/get_allowed_detectors_list").json() + ix = tmp["detectors"].index(self.jf_id) + return tmp["visualisation_address"][ix] + def get_isrunning(self): is_running = ( self.jf_id diff --git a/eco/devices_general/motors.py b/eco/devices_general/motors.py index b5b809f..16f4a75 100755 --- a/eco/devices_general/motors.py +++ b/eco/devices_general/motors.py @@ -603,12 +603,16 @@ class MotorRecord(Assembly): def changer(value): statflag_start = self.status_flag.get_current_value() if not statflag_start.value == 0: - raise AdjustableError(f'Motor {self.alias.get_full_name()}({self.pvname}) cannot start moving with status flag {statflag_start.name} .') + raise AdjustableError( + f"Motor {self.alias.get_full_name()}({self.pvname}) cannot start moving with status flag {statflag_start.name} ." + ) self._status = self._motor.move(value, ignore_limits=(not check), wait=True) self._status_message = _status_messages[self._status] statflag_end = self.status_flag.get_current_value() if not statflag_end.value == 0: - raise AdjustableError(f'Motor {self.alias.get_full_name()}({self.pvname}) cannot finish move with status flag {statflag_end.name} .') + raise AdjustableError( + f"Motor {self.alias.get_full_name()}({self.pvname}) cannot finish move with status flag {statflag_end.name} ." + ) if self._status < 0: raise AdjustableError(self._status_message) diff --git a/eco/dummy/config.py b/eco/dummy/config.py index 555e1fb..f818f54 100755 --- a/eco/dummy/config.py +++ b/eco/dummy/config.py @@ -279,14 +279,14 @@ components = [ "desc": "Attenuator Bernina", "type": "eco.xoptics.attenuator_aramis:AttenuatorAramis", }, - { - "name": "slit_att", - "args": ["SAROP21-OAPU136"], - "kwargs": {}, - "z_und": 136, - "desc": "Slits behind attenuator", - "type": "eco.xoptics.slits:SlitPosWidth", - }, + # { + # "name": "slit_att", + # "args": ["SAROP21-OAPU136"], + # "kwargs": {}, + # "z_und": 136, + # "desc": "Slits behind attenuator", + # "type": "eco.xoptics.slits:SlitPosWidth", + # }, { "name": "det_dio", "args": ["SAROP21-PDIO138"], @@ -373,7 +373,6 @@ components = [ # "type": "tof:jet", # "kwargs": {}, # }, - { "args": ["SARES20-CAMS142-M1"], "name": "cam_sample_sideview", @@ -567,14 +566,6 @@ components = [ "default_file_path": f"/sf/bernina/data/{config['pgroup']}/res/%s", }, }, - { - "args": [], - "name": "usd_table", - "z_und": 141, - "desc": "Upstream diagnostics table", - "type": "eco.endstations.hexapod:HexapodSymmetrie", - "kwargs": {"offset": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]}, - }, # { # "args": ["SARES23-"], # "name": "slit_kb", diff --git a/eco/elements/adjustable.py b/eco/elements/adjustable.py index ab07398..08e6b57 100644 --- a/eco/elements/adjustable.py +++ b/eco/elements/adjustable.py @@ -495,14 +495,16 @@ class AdjustableVirtual: self._active_changers = [ adj.set_target_value(val, hold=False) for val, adj in zip(vals, self._adjustables) + if val is not None ] for tc in self._active_changers: tc.wait() else: for val, adj in zip(vals, self._adjustables): - self._active_changers = [adj.set_target_value(val, hold=False)] - self._active_changers[0].wait() + if val is not None: + self._active_changers = [adj.set_target_value(val, hold=False)] + self._active_changers[0].wait() def stopper(): for tc in self._active_changers: diff --git a/eco/fel/swissfel.py b/eco/fel/swissfel.py index ff38156..1de5a4e 100644 --- a/eco/fel/swissfel.py +++ b/eco/fel/swissfel.py @@ -6,6 +6,7 @@ from ..epics.detector import DetectorPvData, DetectorPvEnum from ..aliases import Alias from datetime import datetime from time import sleep +import numpy as np from ..detector.detectors_psi import DetectorBsStream @@ -248,6 +249,7 @@ class MessageBoard(Assembly): self._append(Message, "SF-OP:ESF-MSG", name="furka_message", is_setting=True) +@spec_convenience class Message: def __init__(self, pvstem, name=None): self.pvname = pvstem @@ -258,36 +260,39 @@ class Message: AdjustablePvString(self.pvname + f":OP-DATE{n + 1}") for n in range(5) ] self.alias = Alias(name, channel=self.pvname + ":OP-MSG1", channeltype="CA") + self.pv_tmp = AdjustablePvString(self.pvname + ":OP-MSG-tmp") def set_new_message(self, message): - for i in range(3, -1, -1): - self.pvs_msg[i + 1].set_target_value( - self.pvs_msg[i].get_current_value() - ).wait() - self.pvs_date[i + 1].set_target_value( - self.pvs_date[i].get_current_value() - ).wait() - timestr = datetime.now().strftime("%a %d-%b-%Y %H:%M:%S") - self.pvs_msg[0].set_target_value(message).wait() - self.pvs_date[0].set_target_value(timestr).wait() + # for i in range(3, -1, -1): + # self.pvs_msg[i + 1].set_target_value( + # self.pvs_msg[i].get_current_value() + # ).wait() + # self.pvs_date[i + 1].set_target_value( + # self.pvs_date[i].get_current_value() + # ).wait() + self.pv_tmp.set_target_value(message).wait() + # timestr = datetime.now().strftime("%a %d-%b-%Y %H:%M:%S") + # self.pvs_msg[0].set_target_value(message).wait() + # self.pvs_date[0].set_target_value(timestr).wait() def get_current_value(self): return self.pvs_msg[0].get_current_value() - def set_target_value(self, value): + def set_target_value(self, value, hold=False): return Changer( target=value, parent=self, changer=self.set_new_message, - hold=True, + hold=hold, stopper=None, ) @spec_convenience class UndulatorK(Assembly): - def __init__(self, name=None): + def __init__(self, maximum_energy_change_keV=1.0, name=None): super().__init__(name=name) + self.maximum_energy_change_keV = maximum_energy_change_keV self._append( DetectorPvData, "SARUN:FELPHOTENE", @@ -332,6 +337,9 @@ class UndulatorK(Assembly): return self.aramis_undulator_photon_energy.get_current_value() def change_energy(self, energy): + if np.abs(energy - self.get_current_value()) > self.maximum_energy_change_keV: + raise Exception("Likely too large undulator energy change requested!!!") + vals = self.calc_new_Ksets(energy) for kset, val in zip(self.ksets, vals): kset.set_target_value(val) diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index 61362a4..23f58c1 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -11,6 +11,7 @@ import colorama import datetime from pint import UnitRegistry import numpy as np +import time # from time import sleep @@ -177,25 +178,37 @@ class LaserBernina(Assembly): MotorRecord, self.pvname + "-M532:MOT", name="compressor", is_setting=True ) # Waveplate and Delay stage - self._append( - MotorRecord, self.pvname + "-M533:MOT", name="wp_pol", is_setting=True - ) - self._append( - MotorRecord, self.pvname + "-M534:MOT", name="wp_att", is_setting=True - ) + # self._append( + # MotorRecord, self.pvname + "-M533:MOT", name="wp_pol", is_setting=True + # ) + + # self._append( + # MotorRecord, self.pvname + "-M534:MOT", name="wp_att", is_setting=True + # ) + + # ad hoc for 500nm setup + self._append(SmaractRecord, "SARES23:ESB3", name="wp_att", is_setting=True) + self._append( AdjustableFS, "/photonics/home/gac-bernina/eco/configuration/wp_att_calibration", name="wp_att_calibration", is_display=False, ) - self._append( - Spectrometer, - "SLAAR02-LSPC-OSC", - name="oscillator_spectrum", - is_setting=False, - is_display=True, - ) + tmptime = time.time() + while (time.time() - tmptime) < 10: + try: + self._append( + Spectrometer, + "SLAAR02-LSPC-OSC", + name="oscillator_spectrum", + is_setting=False, + is_display=True, + ) + print("SUCCESS: oscillator spectrometer configured!") + break + except: + pass def uJ2wp(uJ): direction = 1 @@ -226,9 +239,15 @@ class LaserBernina(Assembly): # ) self._append(XltEpics, name="xlt", is_setting=True, is_display="recursive") # Upstairs, Laser 1 LAM + # self._append( + # MotorRecord, + # "SLAAR21-LMOT-M521:MOTOR_1", + # name="delaystage_pump", + # is_setting=True, + # ) self._append( - MotorRecord, - "SLAAR21-LMOT-M521:MOTOR_1", + SmaractRecord, + "SARES23:ESB1", name="delaystage_pump", is_setting=True, ) diff --git a/eco/timing/lasertiming_edwin.py b/eco/timing/lasertiming_edwin.py index 6ac7098..1b33351 100644 --- a/eco/timing/lasertiming_edwin.py +++ b/eco/timing/lasertiming_edwin.py @@ -10,6 +10,7 @@ from ..elements.adjustable import ( AdjustableFS, AdjustableVirtual, tweak_option, + value_property, ) from ..epics.adjustable import AdjustablePv, AdjustablePvEnum from ..epics.detector import DetectorPvData @@ -168,9 +169,11 @@ from ..elements.assembly import Assembly @spec_convenience @tweak_option +@value_property class XltEpics(Assembly): def __init__(self, pvname="SLAAR02-LTIM-PDLY", name="lxt_epics"): super().__init__(name=name) + self.settings_collection.append(self, force=True) self.pvname = pvname # self.settings_collection.append(self, force=True) # self.status_collection.append(self, force=True) @@ -181,11 +184,11 @@ class XltEpics(Assembly): name="_offset", is_setting=True, is_display=False, - ) + ) # in picoseconds self._append( DetectorPvData, "SLAAR-LGEN:DLY_OFFS2", - unit="µs", + unit="ps", name="delay_user_rb", is_setting=False, is_display=False, @@ -261,7 +264,7 @@ class XltEpics(Assembly): self._append( AdjustablePv, self.pvname + ":P_RATIO", - name="rep_len", + name="ref_pattern_len", is_setting=True, is_display=True, ) @@ -269,13 +272,24 @@ class XltEpics(Assembly): AdjustablePv, "SIN-TIMAST-TMA:Evt-22-Freq-SP", name="laser_frequency", + unit="Hz", is_setting=True, is_display=True, ) self._append( AdjustablePv, self.pvname + ":LONG_DELAY_THRESH", + name="_long_delay_threshold", + is_setting=True, + is_display=False, + ) + self._append( + AdjustableVirtual, + [self._long_delay_threshold], + lambda offset: offset * 1e-12, + lambda offset: offset / 1e-12, name="long_delay_threshold", + unit="s", is_setting=True, is_display=True, ) @@ -308,7 +322,7 @@ class XltEpics(Assembly): # - self.offset.get_current_value() # ) - def change_user_and_wait(self, value, check_interval=0.03): + def change_user_and_wait(self, value, check_interval=0.03, evr_wait_time=0.01): if np.abs(value) > 0.1: raise Exception("Very large value! This value is counted in seconds!") if not self.waiting_for_change.get(): @@ -323,10 +337,18 @@ class XltEpics(Assembly): self.is_stopped = True self.is_moving = new_status - self.waiting_for_change.add_callback(callback=set_is_stopped) + is_phasshift = not ( + self.long_delay_threshold.get_current_value() < np.abs(value) + ) + if is_phasshift: + self.waiting_for_change.add_callback(callback=set_is_stopped) + self._set_dial_delay_value.set_target_value( (value - self.offset.get_current_value()) / 1e-12 ) + if not is_phasshift: + time.sleep(evr_wait_time) + self.is_stopped = True while not self.is_stopped: time.sleep(check_interval) diff --git a/eco/utilities/elog.py b/eco/utilities/elog.py index 3e05454..92a56b0 100755 --- a/eco/utilities/elog.py +++ b/eco/utilities/elog.py @@ -2,6 +2,9 @@ import elog as _elog_ha from getpass import getuser as _getuser from getpass import getpass as _getpass import os, datetime, subprocess +import urllib3 + +urllib3.disable_warnings() def getDefaultElogInstance(url, **kwargs): diff --git a/eco/utilities/runtable.py b/eco/utilities/runtable.py index 15f37c2..030d952 100644 --- a/eco/utilities/runtable.py +++ b/eco/utilities/runtable.py @@ -1061,6 +1061,8 @@ class Run_Table_DataFrame(DataFrame): devices=None, name=None, ): + if type(data) is str: + data = pd.read_pickle(data) super().__init__(data=data) ### Load devices to parse for adjustables ### diff --git a/eco/xoptics/dcm_new.py b/eco/xoptics/dcm_new.py index a4410a2..d33a5b8 100644 --- a/eco/xoptics/dcm_new.py +++ b/eco/xoptics/dcm_new.py @@ -1,4 +1,5 @@ from ..devices_general.motors import MotorRecord, MotorRecord_new +from eco.elements.adjustable import AdjustableFS, AdjustableVirtual from ..epics.adjustable import AdjustablePv, AdjustablePvEnum from ..epics.detector import DetectorPvData from epics import PV @@ -22,12 +23,16 @@ from ..elements.assembly import Assembly class DoubleCrystalMono(Assembly): def __init__( self, - pvname, + pvname=None, name=None, energy_sp="SAROP21-ARAMIS:ENERGY_SP", energy_rb="SAROP21-ARAMIS:ENERGY", + fel=None, + undulator_deadband_eV=None, ): super().__init__(name=name) + self.fel = fel + self.undulator_deadband_eV = undulator_deadband_eV self.pvname = pvname self._append( MotorRecord_new, @@ -86,6 +91,51 @@ class DoubleCrystalMono(Assembly): is_display=False, ) self.settings_collection.append(self) + if self.fel is not None: + self._append( + AdjustableFS, + "/photonics/home/gac-bernina/eco/configuration/mono_und_offset", + name="mono_und_calib", + default_value=[[6500, 0], [7100, 0]], + is_setting=True, + ) + + def en_set(en): + ofs = np.array(self.mono_und_calib()).T + fel_ofs = ofs[1][np.argmin(abs(ofs[0] - en))] + e_und_curr = ( + self.fel.aramis_photon_energy_undulators.get_current_value() + ) + + if ( + np.abs(en - (e_und_curr + fel_ofs) * 1000) + < self.undulator_deadband_eV + ): + return en, None + else: + return en, en / 1000 - fel_ofs + + def en_get(monoen, felen): + return monoen + + self._append( + AdjustableVirtual, + [self.energy, self.fel.aramis_photon_energy_undulators], + en_get, + en_set, + name="mono_und_energy", + ) + + def add_mono_und_calibration_point(self): + mono_energy = self.energy.get_current_value() + fel_offset = ( + self.energy.get_current_value() / 1000 + - self.fel.aramis_photon_energy_undulators.get_current_value() + ) + self.mono_und_calib.mvr([[mono_energy, fel_offset]]) + + def reset_mono_und_calibration(self): + self.mono_und_calib.mv([]) def set_target_value(self, *args, **kwargs): return self.energy.set_target_value(*args, **kwargs) diff --git a/eco/xoptics/dcm_pathlength_compensation.py b/eco/xoptics/dcm_pathlength_compensation.py index 8484153..d85af26 100644 --- a/eco/xoptics/dcm_pathlength_compensation.py +++ b/eco/xoptics/dcm_pathlength_compensation.py @@ -3,6 +3,8 @@ import numpy as np from xrayutilities import materials from ..elements.adjustable import AdjustableFS, AdjustableVirtual from ..elements.assembly import Assembly +from eco import Adjustable +from eco.devices_general.motors import MotorRecord def energy2tthe(energy, hkl=(1, 1, 1), material=materials.Si): @@ -43,7 +45,11 @@ class MonoTimecompensation(Assembly): default_value=True, name="laser_delay_inverted", ) - self._laser_delay = laser_delay_seconds + if isinstance(laser_delay_seconds, Adjustable): + self._laser_delay = laser_delay_seconds + else: + raise Exception("issue getting laser delay for mono compensation") + self._mono_energy = mono_energy_eV self._append( AdjustableVirtual, From f3c85e6842f9eeba35592f38bcfc59db0813939f Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Thu, 23 Feb 2023 18:20:58 +0100 Subject: [PATCH 29/52] fixes --- eco/acquisition/scan.py | 29 +++++- eco/bernina/bernina.py | 180 ++++++++++++++++++----------------- eco/bernina/config.py | 127 +++++++++++------------- eco/loptics/bernina_laser.py | 33 +++---- eco/utilities/config.py | 64 ++++++++++--- 5 files changed, 247 insertions(+), 186 deletions(-) diff --git a/eco/acquisition/scan.py b/eco/acquisition/scan.py index 2110b30..158193c 100755 --- a/eco/acquisition/scan.py +++ b/eco/acquisition/scan.py @@ -54,8 +54,9 @@ class Scan: settling_time=0, checker=None, scan_directories=False, - callbackStartStep=None, callbacks_start_scan=[], + callbacks_start_step=[], + callbacks_end_step=[], callbacks_end_scan=[], checker_sleep_time=2, return_at_end="question", @@ -105,6 +106,8 @@ class Scan: self._elog = elog self.run_number = run_number self.remaining_tasks = [] + self.callbacks_start_step = callbacks_start_step + self.callbacks_end_step = callbacks_end_step self.callbacks_end_scan = callbacks_end_scan self.callbacks_kwargs = kwargs_callbacks print(f"Scan info in file {self.scan_info_filename}.") @@ -147,6 +150,10 @@ class Scan: ) self.checker.clear_and_start_counting() + if self.callbacks_start_step: + for caller in self.callbacks_start_step: + caller(self, **self.callbacks_kwargs) + if not len(self.values_todo) > 0: return False values_step = self.values_todo[0] @@ -226,7 +233,11 @@ class Scan: values_step, readbacks_step, step_files=filenames, step_info=tstepinfo ) self.writeScanInfo() + if self.callbacks_end_step: + for caller in self.callbacks_end_step: + caller(self, **self.callbacks_kwargs) self.nextStep += 1 + return True def appendScanInfo( @@ -299,12 +310,16 @@ class Scans: checker=None, scan_directories=False, callbacks_start_scan=[], + callbacks_start_step=[], + callbacks_end_step=[], callbacks_end_scan=[], run_table=None, elog=None, ): self._run_table = run_table self.callbacks_start_scan = callbacks_start_scan + self.callbacks_start_step = callbacks_start_step + self.callbacks_end_step = callbacks_end_step self.callbacks_end_scan = callbacks_end_scan self.data_base_dir = data_base_dir scan_info_dir = Path(scan_info_dir) @@ -369,6 +384,8 @@ class Scans: checker=self.checker, scan_directories=self._scan_directories, callbacks_start_scan=self.callbacks_start_scan, + callbacks_start_step=self.callbacks_start_step, + callbacks_end_step=self.callbacks_end_step, callbacks_end_scan=self.callbacks_end_scan, run_table=self._run_table, elog=self._elog, @@ -412,6 +429,8 @@ class Scans: checker=self.checker, scan_directories=self._scan_directories, callbacks_start_scan=self.callbacks_start_scan, + callbacks_start_step=self.callbacks_start_step, + callbacks_end_step=self.callbacks_end_step, callbacks_end_scan=self.callbacks_end_scan, run_table=self._run_table, elog=self._elog, @@ -457,6 +476,8 @@ class Scans: scan_directories=self._scan_directories, return_at_end=return_at_end, callbacks_start_scan=self.callbacks_start_scan, + callbacks_start_step=self.callbacks_start_step, + callbacks_end_step=self.callbacks_end_step, callbacks_end_scan=self.callbacks_end_scan, run_table=self._run_table, elog=self._elog, @@ -502,6 +523,8 @@ class Scans: return_at_end=return_at_end, settling_time=settling_time, callbacks_start_scan=self.callbacks_start_scan, + callbacks_start_step=self.callbacks_start_step, + callbacks_end_step=self.callbacks_end_step, callbacks_end_scan=self.callbacks_end_scan, run_table=self._run_table, elog=self._elog, @@ -550,6 +573,8 @@ class Scans: settling_time=settling_time, return_at_end=return_at_end, callbacks_start_scan=self.callbacks_start_scan, + callbacks_start_step=self.callbacks_start_step, + callbacks_end_step=self.callbacks_end_step, callbacks_end_scan=self.callbacks_end_scan, run_table=self._run_table, elog=self._elog, @@ -599,6 +624,8 @@ class Scans: scan_directories=self._scan_directories, return_at_end=return_at_end, callbacks_start_scan=self.callbacks_start_scan, + callbacks_start_step=self.callbacks_start_step, + callbacks_end_step=self.callbacks_end_step, callbacks_end_scan=self.callbacks_end_scan, run_table=self._run_table, elog=self._elog, diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 56e7288..b7df8ed 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -43,13 +43,17 @@ from eco.elements.adj_obj import AdjustableObject namespace.append_obj(AdjustableObject, _config_bernina_dict, name="config_bernina") namespace.append_obj( - "DummyAdjustable", module_name="eco.elements.adjustable", name="dummy_adjustable" + "DummyAdjustable", + module_name="eco.elements.adjustable", + lazy=True, + name="dummy_adjustable", ) namespace.append_obj( "set_global_memory_dir", "/sf/bernina/config/eco/memory", module_name="eco.elements.memory", name="path_memory", + lazy=False, ) namespace.append_obj( @@ -58,7 +62,7 @@ namespace.append_obj( module_name="eco.dbase.archiver", pv_pulse_id="SARES20-CVME-01-EVR0:RX-PULSEID", add_to_cnf=True, - lazy=False, + lazy=True, ) namespace.append_obj( @@ -88,18 +92,6 @@ namespace.append_obj( module_name="eco.elements.adjustable", lazy=True, ) -namespace.append_obj( - "Run_Table2", - name="run_table", - module_name="eco.utilities.runtable", - exp_id=config_bernina.pgroup._value, - exp_path=f"/sf/bernina/data/{config_bernina.pgroup._value}/res/run_table/", - devices="bernina", - keydf_fname="/sf/bernina/config/src/python/gspread/gspread_keys.pkl", - cred_fname="/sf/bernina/config/src/python/gspread/pandas_push", - gsheet_key_path="/sf/bernina/config/eco/reference_values/run_table_gsheet_keys", - lazy=True, -) # adding all stuff from the config components the "old" way of configuring. # whatever is added, it is available by the configured name in this module @@ -633,12 +625,14 @@ namespace.append_obj( namespace.append_obj( "Xspect", name="xspect", + lazy=True, module_name="eco.xdiagnostics.xspect", ) namespace.append_obj( "SlitPosWidth", "SAROP21-OAPU138", name="slit_att", + lazy=True, module_name="eco.xoptics.slits", ), namespace.append_obj( @@ -834,15 +828,18 @@ namespace.append_obj( lazy=True, ) - -# namespace.append_obj( -# "Epicstools", -# name="epics_daq", -# module_name="eco.acquisition.epics_data", -# channel_list=channels_CA_epicsdaq, -# default_file_path=f"/sf/bernina/data/{config_bernina.pgroup}/res/epics_daq/", -# lazy=True, -# ) +namespace.append_obj( + "Run_Table2", + name="run_table", + module_name="eco.utilities.runtable", + exp_id=config_bernina.pgroup._value, + exp_path=f"/sf/bernina/data/{config_bernina.pgroup._value}/res/run_table/", + devices="bernina", + keydf_fname="/sf/bernina/config/src/python/gspread/gspread_keys.pkl", + cred_fname="/sf/bernina/config/src/python/gspread/pandas_push", + gsheet_key_path="/sf/bernina/config/eco/reference_values/run_table_gsheet_keys", + lazy=True, +) def _wait_for_tasks(scan, **kwargs): @@ -951,6 +948,7 @@ def _create_general_run_info(scan, daq=daq, **kwargs): def _copy_scan_info_to_raw(scan, daq=daq, **kwargs): + t_start = time.time() scan.writeScanInfo() @@ -985,9 +983,12 @@ def _copy_scan_info_to_raw(scan, daq=daq, **kwargs): json.dump(si, f, sort_keys=True, cls=NumpyEncoder, indent=4) f.truncate() - print(f"Copying info file to run {runno} to the raw directory of {pgroup}.") + # print(f"Copying info file to run {runno} to the raw directory of {pgroup}.") response = daq.append_aux(scaninfofile.as_posix(), pgroup=pgroup, run_number=runno) - print(f"Status: {response.json()['status']} Message: {response.json()['message']}") + # print(f"Status: {response.json()['status']} Message: {response.json()['message']}") + # print( + # f"--> creating and copying file took{time.time()-t_start} s, presently adding to deadtime." + # ) from eco.detector import Jungfrau @@ -1161,6 +1162,8 @@ callbacks_start_scan.append(_wait_for_tasks) callbacks_start_scan.append(_append_namesace_status_to_scan) callbacks_start_scan.append(_increment_daq_run_number) callbacks_start_scan.append(append_scan_monitors) +callbacks_end_step = [] +callbacks_end_step.append(_copy_scan_info_to_raw) callbacks_end_scan = [] callbacks_end_scan.append(_write_namespace_status_to_scan) callbacks_end_scan.append(_write_namespace_aliases_to_scan) @@ -1231,10 +1234,12 @@ def _create_metadata_structure_start_scan( print("elog posting failed") if not append_status_info: return + t_start_rt = time.time() try: run_table.append_run(runno, metadata=metadata) except: print("WARNING: issue adding data to run table") + print(f"RT appending: {time.time()-t_start_rt:.3f} s") # <<<< Extract for run table and elog @@ -1249,6 +1254,7 @@ namespace.append_obj( checker=checker, scan_directories=True, callbacks_start_scan=callbacks_start_scan, + callbacks_end_step=callbacks_end_step, callbacks_end_scan=callbacks_end_scan, run_table=run_table, elog=elog, @@ -1297,13 +1303,13 @@ namespace.append_obj( module_name="eco.devices_general.cameras_ptz", ) -# namespace.append_obj( -# "BerninaInlineMicroscope", -# pvname_camera="SARES20-CAMS142-M3", -# lazy=True, -# name="samplecam_inline", -# module_name="eco.microscopes", -# ) +namespace.append_obj( + "BerninaInlineMicroscope", + pvname_camera="SARES20-CAMS142-M3", + lazy=True, + name="samplecam_inline", + module_name="eco.microscopes", +) namespace.append_obj( "MicroscopeMotorRecord", @@ -1523,13 +1529,13 @@ namespace.append_obj( name="las_inc", ) -# namespace.append_obj( -# "High_field_thz_chamber", -# name="thc", -# lazy=True, -# module_name="eco.endstations.bernina_sample_environments", -# configuration=["ottifant"], -# ) +namespace.append_obj( + "High_field_thz_chamber", + name="thc", + lazy=True, + module_name="eco.endstations.bernina_sample_environments", + configuration=["ottifant"], +) # class THz_in_air(Assembly): @@ -1653,48 +1659,48 @@ from ..loptics.bernina_laser import DelayTime from ..microscopes import MicroscopeMotorRecord -class JohannAnalyzer(Assembly): - def __init__(self, name=""): - super().__init__(name=name) - self._append( - MotorRecord, - "SARES20-MF1:MOT_3", - name="pitch", - is_setting=True, - is_display=True, - ) - self._append( - MotorRecord, - "SARES20-MF1:MOT_4", - name="roll", - is_setting=True, - is_display=True, - ) +# class JohannAnalyzer(Assembly): +# def __init__(self, name=""): +# super().__init__(name=name) +# self._append( +# MotorRecord, +# "SARES20-MF1:MOT_3", +# name="pitch", +# is_setting=True, +# is_display=True, +# ) +# self._append( +# MotorRecord, +# "SARES20-MF1:MOT_4", +# name="roll", +# is_setting=True, +# is_display=True, +# ) -namespace.append_obj(JohannAnalyzer, name="analyzer") +# namespace.append_obj(JohannAnalyzer, name="analyzer", lazy=True) -class GratingHolder(Assembly): - def __init__(self, name=""): - super().__init__(name=name) - self._append( - MotorRecord, - "SARES20-MF1:MOT_7", - name="vertical", - is_setting=True, - is_display=True, - ) - self._append( - SmaractRecord, - "SARES23:ESB6", - name="horizontal", - is_setting=True, - is_display=True, - ) +# class GratingHolder(Assembly): +# def __init__(self, name=""): +# super().__init__(name=name) +# self._append( +# MotorRecord, +# "SARES20-MF1:MOT_7", +# name="vertical", +# is_setting=True, +# is_display=True, +# ) +# self._append( +# SmaractRecord, +# "SARES23:ESB6", +# name="horizontal", +# is_setting=True, +# is_display=True, +# ) -namespace.append_obj(GratingHolder, name="grating_holder") +# namespace.append_obj(GratingHolder, name="grating_holder") # ad hoc 2 pulse setup @@ -1790,16 +1796,16 @@ namespace.append_obj( lazy=True, module_name="eco.xoptics.dcm_new", ) -namespace.append_obj( - "MonoTimecompensation", - delay_glob, - mono.mono_und_energy, - "/sf/bernina/config/eco/reference_values/dcm_reference_timing.json", - "/sf/bernina/config/eco/reference_values/dcm_reference_invert_delay.json", - lazy=True, - name="mono_time_corrected", - module_name="eco.xoptics.dcm_pathlength_compensation", -) +# namespace.append_obj( +# "MonoTimecompensation", +# delay_glob, +# mono.mono_und_energy, +# "/sf/bernina/config/eco/reference_values/dcm_reference_timing.json", +# "/sf/bernina/config/eco/reference_values/dcm_reference_invert_delay.json", +# lazy=True, +# name="mono_time_corrected", +# module_name="eco.xoptics.dcm_pathlength_compensation", +# ) # ad hoc interferometric timetool @@ -1864,6 +1870,7 @@ namespace.append_obj( bshost=config_bernina.xeye.bshost._value, bsport=config_bernina.xeye.bsport._value, name="xeye", + lazy=True, module_name="eco.xdiagnostics.profile_monitors", ) @@ -1989,9 +1996,10 @@ class LiquidJetSpectroscopy(Assembly): self._append( Jungfrau, "JF14T01V01", name="det_vhamos", pgroup_adj=config_bernina.pgroup ) + self._append(CameraBasler, "SARES20-CAMS142-M2", name="prof_pump") -namespace.append_obj(LiquidJetSpectroscopy, name="jet", lazy=True) +# namespace.append_obj(LiquidJetSpectroscopy, name="jet", lazy=True) # class Tapedrive(Assembly): diff --git a/eco/bernina/config.py b/eco/bernina/config.py index e61e201..e59a687 100755 --- a/eco/bernina/config.py +++ b/eco/bernina/config.py @@ -46,21 +46,21 @@ components = [ "args": [], "kwargs": {"screenshot_directory": "/sf/bernina/config/screenshots"}, }, -# { -# "name": "fel", -# "type": "eco.fel.swissfel:SwissFel", -# "args": [], -# "kwargs": {}, -# "desc": "Fel related control and feedback", -# }, -# { -# "name": "mono", -# "args": ["SAROP21-ODCM098"], -# "kwargs": {}, -# "z_und": 98, -# "desc": "DCM Monochromator", -# "type": "eco.xoptics.dcm_new:DoubleCrystalMono", -# }, + # { + # "name": "fel", + # "type": "eco.fel.swissfel:SwissFel", + # "args": [], + # "kwargs": {}, + # "desc": "Fel related control and feedback", + # }, + # { + # "name": "mono", + # "args": ["SAROP21-ODCM098"], + # "kwargs": {}, + # "z_und": 98, + # "desc": "DCM Monochromator", + # "type": "eco.xoptics.dcm_new:DoubleCrystalMono", + # }, # { # "name": "slit_und", # "type": "eco.xoptics.slits:SlitFourBlades_old", @@ -153,14 +153,14 @@ components = [ # "args": ["SARFE10-PBPS053"], # "kwargs": {}, # }, - { - "name": "xspect", - "z_und": 53, - "desc": "X-ray single shot spectrometer", - "type": "eco.xdiagnostics.xspect:Xspect", - "args": [], - "kwargs": {}, - }, + # { + # "name": "xspect", + # "z_und": 53, + # "desc": "X-ray single shot spectrometer", + # "type": "eco.xdiagnostics.xspect:Xspect", + # "args": [], + # "kwargs": {}, + # }, { "name": "prof_fe", "args": ["SARFE10-PPRM064"] * 2, @@ -194,17 +194,17 @@ components = [ "type": "eco.xoptics.offsetMirrors_new:OffsetMirrorsBernina", "kwargs": {}, }, - { - "name": "mono_old", - "args": ["SAROP21-ODCM098"], - "kwargs": { - "energy_sp": "SAROP21-ARAMIS:ENERGY_SP", - "energy_rb": "SAROP21-ARAMIS:ENERGY", - }, - "z_und": 98, - "desc": "DCM Monochromator", - "type": "eco.xoptics.dcm:Double_Crystal_Mono", - }, + # { + # "name": "mono_old", + # "args": ["SAROP21-ODCM098"], + # "kwargs": { + # "energy_sp": "SAROP21-ARAMIS:ENERGY_SP", + # "energy_rb": "SAROP21-ARAMIS:ENERGY", + # }, + # "z_und": 98, + # "desc": "DCM Monochromator", + # "type": "eco.xoptics.dcm:Double_Crystal_Mono", + # }, { "name": "prof_mono", "args": ["SAROP21-PPRM113"] * 2, @@ -279,14 +279,14 @@ components = [ "desc": "Attenuator Bernina", "type": "eco.xoptics.attenuator_aramis:AttenuatorAramis", }, - { - "name": "slit_att", - "args": ["SAROP21-OAPU136"], - "kwargs": {}, - "z_und": 136, - "desc": "Slits behind attenuator", - "type": "eco.xoptics.slits:SlitPosWidth", - }, + # { + # "name": "slit_att", + # "args": ["SAROP21-OAPU136"], + # "kwargs": {}, + # "z_und": 136, + # "desc": "Slits behind attenuator", + # "type": "eco.xoptics.slits:SlitPosWidth", + # }, # { # "name": "det_dio", # "args": ["SAROP21-PDIO138"], @@ -452,21 +452,6 @@ components = [ # }, # { # "args": [], - # "name": "scans_epics", - # "desc": "epics non beam synchronous based acquisition", - # "type": "eco.acquisition.scan:Scans", - # "kwargs": { - # "data_base_dir": "scan_data", - # "scan_info_dir": f"/sf/bernina/data/{config['pgroup']}/res/scan_info", - # "default_counters": [Component("epics_daq")], - # "checker": Component("checker_epics"), - # "scan_directories": True, - # "run_table": Component("run_table"), - # }, - # "lazy": True, - # }, - # { - # "args": [], # "name": "lxt", # "desc": "laser timing with pockels cells and phase shifter", # "type": "eco.timing.lasertiming:Lxt", @@ -542,20 +527,20 @@ components = [ # "type": "eco.xoptics.slit_USD:Upstream_diagnostic_slits", # "kwargs": {"right": "LIC7", "left": "LIC8", "up": "LIC8", "down": "LIC5"}, # }, - { - "args": [ - [ - Component("slit_und"), - Component("slit_switch"), - Component("slit_att"), - Component("slit_kb"), - ] - ], - "name": "slits", - "desc": "collection of all slits", - "type": "eco.utilities.beamline:Slits", - "kwargs": {}, - }, + # { + # "args": [ + # [ + # Component("slit_und"), + # Component("slit_switch"), + # Component("slit_att"), + # Component("slit_kb"), + # ] + # ], + # "name": "slits", + # "desc": "collection of all slits", + # "type": "eco.utilities.beamline:Slits", + # "kwargs": {}, + # }, # { # "args": [ # [Component("slit_switch"), Component("slit_att"), Component("slit_kb"),] diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index 23f58c1..4764729 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -353,33 +353,34 @@ class DelayCompensation(AdjustableVirtual): class PositionMonitors(Assembly): def __init__(self, name=None): super().__init__(name=name) + self._append( + CameraPositionMonitor, + "SLAAR21-LCAM-C541", + name="table1_angle", + is_display="recursive", + is_status=True, + ) self._append( CameraPositionMonitor, "SLAAR21-LCAM-C551", - name="post_compressor_focus", + name="table2_angle", is_display="recursive", is_status=True, ) self._append( CameraPositionMonitor, "SLAAR21-LCAM-C552", - name="post_compressor_position", - is_display="recursive", - is_status=True, - ) - self._append( - CameraPositionMonitor, - "SLAAR21-LCAM-C531", - name="opaout_position", - is_display="recursive", - is_status=True, - ) - self._append( - CameraPositionMonitor, - "SLAAR21-LCAM-C511", - name="opaout_focus", + name="table2_position", is_display="recursive", is_status=True, ) + + # self._append( + # CameraPositionMonitor, + # "SLAAR21-LCAM-C511", + # name="opaout_focus", + # is_display="recursive", + # is_status=True, + # ) # self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C541', name='cam541') # self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C542', name='cam542') diff --git a/eco/utilities/config.py b/eco/utilities/config.py index 6b770b8..cf83196 100644 --- a/eco/utilities/config.py +++ b/eco/utilities/config.py @@ -266,6 +266,8 @@ class Namespace(Assembly): # self.name = name self.lazy_items = {} self.initialized_items = {} + self.failed_items = {} + self.initialisation_times = {} self.names_without_alias = [] self.root_module = root_module self.alias_namespace = alias_namespace @@ -278,9 +280,13 @@ class Namespace(Assembly): def lazy_names(self): return set(self.lazy_items.keys()) + @property + def failed_names(self): + return set(self.failed_items.keys()) + @property def all_names(self): - return self.initialized_names | self.lazy_names + return self.initialized_names | self.lazy_names | self.failed_names def init_name(self, name, verbose=True, raise_errors=False): # for name in self.all_names: @@ -290,17 +296,24 @@ class Namespace(Assembly): # if verbose: # print(("(%s)" % (name)).ljust(25), end="") # sys.stdout.flush() + starttime = time() try: dir(self.get_obj(name)) if verbose: - print((_color.GREEN + "OK" + _color.RESET).rjust(5)) + print( + f"{time()-starttime} s " + + (_color.GREEN + "OK" + _color.RESET).rjust(5) + ) sys.stdout.flush() except Exception as expt: # tb = traceback.format_exc() if verbose: - print((_color.RED + "FAILED" + _color.RESET).rjust(5)) + print( + f"{time()-starttime} s " + + (_color.RED + "FAILED" + _color.RESET).rjust(5) + ) # print(sys.exc_info()) if raise_errors: raise expt @@ -313,12 +326,18 @@ class Namespace(Assembly): max_workers=5, N_cycles=4, silent=True, + giveup_failed=True, ): starttime = time() + + if self.failed_names: + print( + f"WARNING - previously hard failed items are NOT initialized:\n{self.failed_names} " + ) if silent: self.silently_initializing = True print( - f"Initializeing all items in namespace {self.name} silently in background.\n Be aware of unrelated output!" + f"Initializing all items in namespace {self.name} silently in background.\n Be aware of unrelated output!" ) def init(): @@ -339,11 +358,19 @@ class Namespace(Assembly): ] self.exc_init.shutdown(wait=True) self.silently_initializing = False + if giveup_failed: + failed_names = self.lazy_names + for k in failed_names: + self.failed_items[k] = self.lazy_items.pop(k) if print_summary: print( f"Initialized {len(self.initialized_names)} of {len(self.all_names)}." ) - print("Failed objects: " + ", ".join(self.lazy_names)) + print( + "Failed objects: " + + ", ".join(self.lazy_names.union(self.failed_names)) + ) + print(f"Initialisation took {time()-starttime} seconds") Thread(target=init).start() else: @@ -356,10 +383,10 @@ class Namespace(Assembly): lambda name: self.init_name( name, verbose=verbose, raise_errors=raise_errors ), - self.all_names, + self.all_names - self.initialized_names, ), description="Initializing ...", - total=len(self.all_names), + total=len(self.all_names - self.initialized_names), transient=True, ) ) @@ -371,21 +398,27 @@ class Namespace(Assembly): lambda name: self.init_name( name, verbose=verbose, raise_errors=raise_errors ), - self.all_names, + self.all_names - self.initialized_names, ), description="Initializing ...", - total=len(self.all_names), + total=len(self.all_names - self.initialized_names), transient=True, ) ) # ) # # ) - + if giveup_failed: + failed_names = self.lazy_names + for k in failed_names: + self.failed_items[k] = self.lazy_items.pop(k) if print_summary: print( f"Initialized {len(self.initialized_names)} of {len(self.all_names)}." ) - print("Failed objects: " + ", ".join(self.lazy_names)) + print( + "Failed objects: " + + ", ".join(self.lazy_names.union(self.failed_names)) + ) print(f"Initialisation took {time()-starttime} seconds") # if verbose: @@ -432,6 +465,7 @@ class Namespace(Assembly): if lazy: def init_local(): + starttime = time() if module_name: obj_maker = getattr(import_module(module_name), obj_factory) else: @@ -442,7 +476,11 @@ class Namespace(Assembly): else: obj_initialized = obj_maker(*args, **kwargs) - self.initialized_items[name] = self.lazy_items.pop(name) + try: + self.initialized_items[name] = self.lazy_items.pop(name) + except KeyError: + self.initialized_items[name] = self.failed_items.pop(name) + self.initialisation_times[name] = time() - starttime if hasattr(obj_initialized, "alias"): self._append( obj_initialized, @@ -472,6 +510,7 @@ class Namespace(Assembly): return obj_lazy else: + starttime = time() if module_name: obj_maker = getattr(import_module(module_name), obj_factory) else: @@ -481,6 +520,7 @@ class Namespace(Assembly): except TypeError: obj = obj_maker(*args, **kwargs) self.initialized_items[name] = obj + self.initialisation_times[name] = time() - starttime if self.root_module: sys.modules[self.root_module].__dict__[name] = obj if hasattr(obj, "alias"): From 97f392ed176093c4ced0768aa509faac920e1c93 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Fri, 24 Feb 2023 09:06:23 +0100 Subject: [PATCH 30/52] fixes --- eco/dummy/__init__.py | 82 --- eco/dummy/bernina.py | 1165 ---------------------------------- eco/dummy/config.py | 655 ------------------- eco/dummy/dummy.py | 32 - eco/loptics/bernina_laser.py | 14 +- eco/utilities/config.py | 19 +- 6 files changed, 20 insertions(+), 1947 deletions(-) delete mode 100644 eco/dummy/__init__.py delete mode 100644 eco/dummy/bernina.py delete mode 100755 eco/dummy/config.py delete mode 100644 eco/dummy/dummy.py diff --git a/eco/dummy/__init__.py b/eco/dummy/__init__.py deleted file mode 100644 index 4b03e56..0000000 --- a/eco/dummy/__init__.py +++ /dev/null @@ -1,82 +0,0 @@ -from .dummy import * - -# from ..utilities.config import initFromConfigList -# from epics import PV -# from .. import ecocnf -# from ..aliases import NamespaceCollection -# import logging - -# from .config import components, config -# import sys - - -# _namespace = globals() - -# _mod = sys.modules[__name__] - -# _scope_name = "bernina" - -# alias_namespaces = NamespaceCollection() - - -# # from ..utilities.runtable import Run_Table -# # def init(pgroup, alias_namespaces, instances): -# # run_table = Run_Table(pgroup, alias_namespaces.bernina, instances) -# # return run_table -# def init(*args, lazy=None): -# if args: -# allnames = [tc["name"] for tc in components] -# comp_toinit = [] -# for arg in args: -# if not arg in allnames: -# raise Exception(f"The component {arg} has no configuration defined!") -# else: -# comp_toinit.append(components[allnames.index(arg)]) -# else: -# comp_toinit = components - -# if lazy is None: -# lazy = ecocnf.startup_lazy - -# op = {} -# for key, value in initFromConfigList(comp_toinit, components, lazy=lazy).items(): -# # _namespace[key] = value -# _mod.__dict__[key] = value -# op[key] = value -# if not lazy: -# print("made here") -# if hasattr(value, "alias"): -# for ta in value.alias.get_all(): -# try: -# alias_namespaces.bernina.update( -# ta["alias"], ta["channel"], ta["channeltype"] -# ) -# except: -# print(f'could not init alias {ta["alias"]}') -# else: -# print(f"object {key} has no alias!") -# alias_namespaces.bernina.store() -# # try: -# # run_table = bernina.init(config['pgroup'], alias_namespaces,_mod) -# # _mod.__dict__['rt'] = run_table -# # op['rt'] = run_table -# # except: -# # print('Initializing of run_table failed') -# return op - - -# def parse_for_aliases(): -# names = [tc["name"] for tc in components] -# for name in names: -# to = _mod.__dict__[name] -# if hasattr(to, "alias"): -# for ta in to.alias.get_all(): -# try: -# globals()["alias_namespaces"].bernina.update( -# ta["alias"], ta["channel"], ta["channeltype"] -# ) -# except: -# print(f'could not init alias {ta["alias"]}') -# else: -# print(f"object {name} has no alias!") -# globals()["alias_namespaces"].bernina.store() diff --git a/eco/dummy/bernina.py b/eco/dummy/bernina.py deleted file mode 100644 index 02dc2d0..0000000 --- a/eco/dummy/bernina.py +++ /dev/null @@ -1,1165 +0,0 @@ -from eco.elements.adjustable import AdjustableFS -from eco.motion.smaract import SmaractController -from .config import components -from .config import config as config_berninamesp -from ..utilities.config import Namespace -from ..aliases import NamespaceCollection -import pyttsx3 - -from ..utilities.path_alias import PathAlias -import sys, os -from IPython import get_ipython - - -path_aliases = PathAlias() -sys.path.append("/sf/bernina/config/src/python/bernina_analysis") - -namespace = Namespace( - name="bernina", root_module=__name__, alias_namespace=NamespaceCollection().bernina -) -namespace.alias_namespace.data = [] - -# Adding stuff that might be relevant for stuff configured below (e.g. config) - -_config_bernina_dict = AdjustableFS( - "/sf/bernina/config/eco/configuration/bernina_config.json", - name="_config_bernina_dict", -) -from eco.elements.adj_obj import AdjustableObject - -namespace.append_obj(AdjustableObject, _config_bernina_dict, name="config_bernina") - -namespace.append_obj( - "DummyAdjustable", module_name="eco.elements.adjustable", name="dummy_adjustable" -) -namespace.append_obj( - "set_global_memory_dir", - "/sf/bernina/config/eco/memory", - module_name="eco.elements.memory", - name="path_memory", -) - -namespace.append_obj( - "DataApi", - name="archiver", - module_name="eco.dbase.archiver", - pv_pulse_id="SARES20-CVME-01-EVR0:RX-PULSEID", - add_to_cnf=True, - lazy=False, -) - -namespace.append_obj( - "BerninaEnv", - name="env_log", - module_name="eco.fel.atmosphere", - lazy=True, -) -namespace.append_obj( - "AdjustableFS", - "/photonics/home/gac-bernina/eco/configuration/run_table_channels_CA", - name="_env_channels_ca", - module_name="eco.elements.adjustable", -) -namespace.append_obj( - "Run_Table2", - name="run_table", - module_name="eco.utilities.runtable", - exp_id=config_bernina.pgroup.value, - exp_path=f"/sf/bernina/data/{config_bernina.pgroup.value}/res/run_table/", - devices="bernina", - keydf_fname="/sf/bernina/config/src/python/gspread/gspread_keys.pkl", - cred_fname="/sf/bernina/config/src/python/gspread/pandas_push", - gsheet_key_path="/sf/bernina/config/eco/reference_values/run_table_gsheet_keys", - lazy=True, -) - -# adding all stuff from the config components the "old" way of configuring. -# whatever is added, it is available by the configured name in this module -# afterwards, and can be used immediately, e.g. as input argument for the next thing. - -for tk in components: - namespace.append_obj_from_config(tk, lazy=True) - - -# Adding stuff the "new" way - -# namespace.append_obj( -# "EventReceiver", -# "", -# lazy=True, -# name="cam_north", -# module_name="eco.devices_general.cameras_ptz", -# ) - - -## beamline components ## - -namespace.append_obj( - "JJSlitUnd", - name="slit_und", - module_name="eco.xoptics.slits", - lazy=True, -) -namespace.append_obj( - "SlitBlades", - "SAROP21-OAPU092", - name="slit_switch", - module_name="eco.xoptics.slits", -) -namespace.append_obj( - "SlitBlades", - "SAROP21-OAPU102", - name="slit_mono", - module_name="eco.xoptics.slits", -) - -from eco.devices_general.motors import SmaractStreamdevice, SmaractRecord - -namespace.append_obj( - "SlitBladesGeneral", - name="slit_kb", - def_blade_up={ - "args": [SmaractRecord, "SARES23:LIC2"], - "kwargs": {}, - }, - def_blade_down={ - "args": [SmaractRecord, "SARES23:LIC1"], - "kwargs": {}, - }, - def_blade_left={ - "args": [SmaractRecord, "SARES23:LIC9"], - "kwargs": {}, - }, - def_blade_right={ - "args": [SmaractRecord, "SARES23:LIC4"], - "kwargs": {}, - }, - module_name="eco.xoptics.slits", - lazy=True, -) -# namespace.append_obj( -# "SlitBladesGeneral", -# name="slit_kb", -# def_blade_up={ -# "args": [SmaractStreamdevice, "SARES23-LIC2"], -# "kwargs": { -# "offset_file": "/sf/bernina/config/eco/reference_values/slit_kb_up.json", -# }, -# }, -# def_blade_down={ -# "args": [SmaractStreamdevice, "SARES23-LIC1"], -# "kwargs": { -# "offset_file": "/sf/bernina/config/eco/reference_values/slit_kb_down.json", -# }, -# }, -# def_blade_left={ -# "args": [SmaractStreamdevice, "SARES23-LIC3"], -# "kwargs": { -# "offset_file": "/sf/bernina/config/eco/reference_values/slit_kb_left.json", -# }, -# }, -# def_blade_right={ -# "args": [SmaractStreamdevice, "SARES23-LIC4"], -# "kwargs": { -# "offset_file": "/sf/bernina/config/eco/reference_values/slit_kb_right.json", -# }, -# }, -# module_name="eco.xoptics.slits", -# lazy=True, -# ) - - -namespace.append_obj( - "SlitBladesGeneral", - name="slit_cleanup", - def_blade_up={ - "args": [SmaractRecord, "SARES23:LIC6"], - "kwargs": {}, - }, - def_blade_down={ - "args": [SmaractRecord, "SARES23:LIC5"], - "kwargs": {}, - }, - def_blade_left={ - "args": [SmaractRecord, "SARES23:LIC8"], - "kwargs": {}, - }, - def_blade_right={ - "args": [SmaractRecord, "SARES23:LIC7"], - "kwargs": {}, - }, - module_name="eco.xoptics.slits", - lazy=True, -) -# namespace.append_obj( -# "SlitBladesGeneral", -# name="slit_cleanup", -# def_blade_up={ -# "args": [SmaractStreamdevice, "SARES23-LIC6"], -# "kwargs": { -# "offset_file": "/sf/bernina/config/eco/reference_values/slit_cleanup_up.json", -# }, -# }, -# def_blade_down={ -# "args": [SmaractStreamdevice, "SARES23-LIC5"], -# "kwargs": { -# "offset_file": "/sf/bernina/config/eco/reference_values/slit_cleanup_down.json", -# }, -# }, -# def_blade_left={ -# "args": [SmaractStreamdevice, "SARES23-LIC8"], -# "kwargs": { -# "offset_file": "/sf/bernina/config/eco/reference_values/slit_cleanup_left.json", -# }, -# }, -# def_blade_right={ -# "args": [SmaractStreamdevice, "SARES23-LIC7"], -# "kwargs": { -# "offset_file": "/sf/bernina/config/eco/reference_values/slit_cleanup_right.json", -# }, -# }, -# module_name="eco.xoptics.slits", -# lazy=True, -# ) - -namespace.append_obj( - "GasDetector", - name="mon_und_gas", - module_name="eco.xdiagnostics.intensity_monitors", - lazy=True, -) -namespace.append_obj( - "RefLaser_Aramis", - "SAROP21-OLAS136", - module_name="eco.xoptics.reflaser_new", - name="reflaser", - lazy=True, -) -namespace.append_obj( - "SolidTargetDetectorPBPS_assi", - "SAROP21-PBPS133", - pvname_fedigitizerchannels=dict( - up="SAROP21-CVME-PBPS1:Lnk9Ch0", - down="SAROP21-CVME-PBPS1:Lnk9Ch12", - left="SAROP21-CVME-PBPS1:Lnk9Ch15", - right="SAROP21-CVME-PBPS1:Lnk9Ch13", - ), - name="mon_opt_dev", - module_name="eco.xdiagnostics.intensity_monitors", - lazy=True, -) - - -namespace.append_obj( - "Pprm_dsd", - pvname="SARES20-DSDPPRM", - pvname_camera="SARES20-DSDPPRM", - module_name="eco.xdiagnostics.profile_monitors", - name="prof_dsd", - lazy=True, -) -namespace.append_obj( - "SolidTargetDetectorPBPS_new_assembly", - pvname="SARES20-DSDPBPS", - module_name="eco.xdiagnostics.intensity_monitors", - name="mon_dsd", - lazy=True, -) - -## general components ## -namespace.append_obj( - "CtaSequencer", - "SAR-CCTA-ESB", - 0, - name="seq", - module_name="eco.timing.sequencer", - lazy=True, -) -namespace.append_obj( - "MasterEventSystem", - "SIN-TIMAST-TMA", - name="event_master", - module_name="eco.timing.event_timing_new_new", - # lazy=False, - lazy=True, -) -# namespace.append_obj("TimingSystem",pv_master="SIN-TIMAST-TMA",pv_pulse_id="SARES20-CVME-01-EVR0:RX-PULSEID",name='event_system',module_name = "eco.timing.event_timing_new_new",lazy=True) - -# namespace.append_obj('Daq', instrument= "bernina",pgroup= config_berninamesp["pgroup"], channels_JF=channels_JF, channels_BS=channels_BS,channels_BSCAM=channels_BSCAM,channels_CA=channels_CA,pulse_id_adj="SLAAR21-LTIM01-EVR0:RX-PULSEID",event_master=event_system.event_master,detectors_event_code=50,name='daq',module_name='eco.acquisition.daq_client') - -# namespace.append_obj('Scans',data_base_dir="scan_data",scan_info_dir=f"/sf/bernina/data/{config_berninamesp['pgroup']}/res/scan_info", -# default_counters=[daq],checker=checker,scan_directories=True,run_table=run_table,elog=elog, -# module_name = "eco.acquisition.scan",name="scans") -namespace.append_obj( - "ProfKbBernina", - module_name="eco.xdiagnostics.profile_monitors", - name="prof_kb", - pvname_mirror="SARES23:LIC11", - lazy=True, -) -namespace.append_obj( - "TimetoolBerninaUSD", - module_name="eco.timing.timing_diag", - pvname_mirror="SARES23:LIC11", - name="tt_kb", - lazy=True, -) - -namespace.append_obj( - "EventReceiver", - "SARES20-CVME-01-EVR0", - event_master, - n_pulsers=24, - n_output_front=7, - n_output_rear=16, - name="evr", - module_name="eco.timing.event_timing_new_new", - lazy=True, -) -namespace.append_obj( - "EventReceiver", - "SLAAR-LTIM02-EVR0", - event_master, - n_pulsers=24, - n_output_front=7, - n_output_rear=16, - name="evr_laser", - module_name="eco.timing.event_timing_new_new", - lazy=True, -) -namespace.append_obj( - "EventReceiver", - "SLAAR21-LTIM01-EVR0", - event_master, - n_pulsers=24, - n_output_front=7, - n_output_rear=16, - name="evr_hutch_laser", - module_name="eco.timing.event_timing_new_new", - lazy=True, - # lazy=False, -) -namespace.append_obj( - "EventReceiver", - "SGE-CPCW-72-EVR0", - event_master, - n_pulsers=16, - n_output_front=16, - n_output_rear=0, - name="evr_camserver72", - module_name="eco.timing.event_timing_new_new", - lazy=True, - # lazy=False, -) -namespace.append_obj( - "EventReceiver", - "SGE-CPCW-83-EVR0", - event_master, - n_pulsers=16, - n_output_front=16, - n_output_rear=0, - name="evr_camserver83", - module_name="eco.timing.event_timing_new_new", - lazy=True, - # lazy=False, -) -namespace.append_obj( - "EventReceiver", - "SGE-CPCW-84-EVR0", - event_master, - n_pulsers=16, - n_output_front=16, - n_output_rear=0, - name="evr_camserver84", - module_name="eco.timing.event_timing_new_new", - lazy=True, - # lazy=False, -) -namespace.append_obj( - "EventReceiver", - "SGE-CPCW-85-EVR0", - event_master, - n_pulsers=16, - n_output_front=16, - n_output_rear=0, - name="evr_camserver85", - module_name="eco.timing.event_timing_new_new", - lazy=True, - # lazy=False, -) - -namespace.append_obj( - "AxisPTZ", - "bernina-cam-n", - lazy=True, - name="cam_north", - module_name="eco.devices_general.cameras_ptz", -) -namespace.append_obj( - "AxisPTZ", - "bernina-cam-w", - lazy=True, - name="cam_west", - module_name="eco.devices_general.cameras_ptz", -) -namespace.append_obj( - "AxisPTZ", - "bernina-cam-s", - lazy=True, - name="cam_south", - module_name="eco.devices_general.cameras_ptz", -) -namespace.append_obj( - "WagoAnalogInputs", - "SARES20-CWAG-GPS01", - lazy=True, - name="analog_inputs", - module_name="eco.devices_general.wago", -) -namespace.append_obj( - "GudeStrip", - "SARES20-CPPS-01", - lazy=True, - name="powerstrip_gps", - module_name="eco.devices_general.powersockets", -) -namespace.append_obj( - "GudeStrip", - "SARES20-CPPS-04", - lazy=True, - name="powerstrip_xrd", - module_name="eco.devices_general.powersockets", -) -namespace.append_obj( - "GudeStrip", - "SARES20-CPPS-02", - lazy=True, - name="powerstrip_patch2", - module_name="eco.devices_general.powersockets", -) -namespace.append_obj( - "GPS", - module_name="eco.endstations.bernina_diffractometers", - name="gps", - pvname="SARES22-GPS", - configuration=config_bernina.gps_config(), - fina_hex_angle_offset="/sf/bernina/config/eco/reference_values/hex_pi_angle_offset.json", - lazy=True, -) -namespace.append_obj( - "XRDYou", - module_name="eco.endstations.bernina_diffractometers", - Id="SARES21-XRD", - configuration=config_bernina.xrd_config(), - diff_detector={"jf_id": "JF01T03V01"}, - invert_kappa_ellbow=config_bernina.invert_kappa_ellbow.value, - name="xrd", - lazy=True, -) - -namespace.append_obj( - "HexapodSymmetrie", - name="usd_table", - module_name="eco.endstations.hexapod", - offset=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0], -) - -namespace.append_obj( - "KBMirrorBernina_new", - "SAROP21-OKBV139", - "SAROP21-OKBH140", - module_name="eco.xoptics.kb_bernina", - usd_table=usd_table, - name="kb", - diffractometer=xrd, -) - -### channelsfor daq ### -namespace.append_obj( - "AdjustableFS", - "/photonics/home/gac-bernina/eco/configuration/channels_JF", - module_name="eco.elements.adjustable", - lazy=True, - name="channels_JF", -) -namespace.append_obj( - "AdjustableFS", - "/photonics/home/gac-bernina/eco/configuration/config_JFs", - module_name="eco.elements.adjustable", - lazy=True, - name="config_JFs", -) -namespace.append_obj( - "AdjustableFS", - "/photonics/home/gac-bernina/eco/configuration/channels_BS", - module_name="eco.elements.adjustable", - lazy=True, - name="channels_BS", -) -namespace.append_obj( - "AdjustableFS", - "/photonics/home/gac-bernina/eco/configuration/channels_BSCAM", - module_name="eco.elements.adjustable", - lazy=True, - name="channels_BSCAM", -) -namespace.append_obj( - "AdjustableFS", - "/photonics/home/gac-bernina/eco/configuration/channels_CA", - module_name="eco.elements.adjustable", - lazy=True, - name="channels_CA", -) -namespace.append_obj( - "AdjustableFS", - "/photonics/home/gac-bernina/eco/configuration/channels_CA_epicsdaq", - module_name="eco.elements.adjustable", - lazy=True, - name="channels_CA_epicsdaq", -) - -namespace.append_obj( - "Att_usd", - name="att_usd", - module_name="eco.xoptics.att_usd", - xp=xp, -) - - -### draft new epics daq ### -# namespace.append_obj( -# "EpicsDaq", -# default_file_path=f"/sf/bernina/data/{config_berninamesp['pgroup']}/res/epics_daq/", -# channels_list=channels_CA_epicsdaq, -# name="daq_epics_local", -# module_name="eco.acquisition.epics_data", -# lazy=True, -# ) -### old epics daq ### -# namespace.append_obj( -# "ChannelList", -# name="epics_channel_list", -# file_name="/sf/bernina/config/channel_lists/default_channel_list_epics", -# module_name="eco.utilities.config", -# ) - -# namespace.append_obj( -# "Epicstools", -# name="epics_daq", -# channel_list=epics_channel_list, -# default_file_path=f"/sf/bernina/data/{config_berninamesp['pgroup']}/res/epics_daq/", -# module_name="eco.acquisition.epics_data", -# ) - -# namespace.append_obj( -# "Scans", -# name="scans_epics", -# module_name="eco.acquisition.scan", -# data_base_dir="scan_data", -# scan_info_dir=f"/sf/bernina/data/{config_berninamesp['pgroup']}/res/scan_info", -# default_counters=[epics_daq], -# checker=checker_epics, -# scan_directories=True, -# run_table=run_table, -# ) -# -# -##### standard DAQ ####### -namespace.append_obj( - "Daq", - instrument="bernina", - pgroup=config_bernina.pgroup(), - channels_JF=channels_JF, - channels_BS=channels_BS, - channels_BSCAM=channels_BSCAM, - channels_CA=channels_CA, - config_JFs=config_JFs, - pulse_id_adj="SLAAR21-LTIM01-EVR0:RX-PULSEID", - event_master=event_master, - detectors_event_code=50, - name="daq", - module_name="eco.acquisition.daq_client", - lazy=True, -) -namespace.append_obj( - "Daq", - instrument="bernina", - broker_address="http://sf-daq-1:10002", - pgroup=config_bernina.pgroup, - channels_JF=channels_JF, - channels_BS=channels_BS, - channels_BSCAM=channels_BSCAM, - channels_CA=channels_CA, - config_JFs=config_JFs, - pulse_id_adj="SLAAR21-LTIM01-EVR0:RX-PULSEID", - event_master=event_master, - detectors_event_code=50, - name="daq_dev", - module_name="eco.acquisition.daq_client", - lazy=True, -) - - -def _append_namesace_status_to_scan(scan): - scan.scan_info["scan_parameters"]["namespace_status"] = namespace.get_status( - base=None - ) - - -def _append_namespace_aliases_to_scan(scan): - scan.scan_info["scan_parameters"]["namespace_aliases"] = namespace.alias.get_all() - - -def _message_end_scan(scan): - e = pyttsx3.init() - e.say(f"Finished run {scan.run_number}.") - e.runAndWait() - e.stop() - - -def _copy_scan_info_to_raw(scan, daq=daq): - run_number = daq.get_last_run_number() - pgroup = daq.pgroup - print(f"Copying info file to run {run_number} to the raw directory of {pgroup}.") - response = daq.append_aux( - scan.scan_info_filename, pgroup=pgroup, run_number=run_number - ) - print(f"Status: {response.json()['status']} Message: {response.json()['message']}") - - -def _increment_daq_run_number(scan, daq=daq): - try: - daq_last_run_number = daq.get_last_run_number() - if int(scan.run_number) is int(daq_last_run_number) + 1: - daq_run_number = daq.get_next_run_number() - else: - daq_run_number = daq_last_run_number - if int(scan.run_number) is not int(daq_run_number): - print( - f"Difference in run number between eco {int(scan.run_number)} and daq {int(daq_run_number)}: using run number {int(scan.run_number)}" - ) - if int(scan.run_number) > int(daq_run_number): - n = int(scan.run_number) - int(daq_run_number) - print("Increasing daq run_number") - for i in range(n): - rn = daq.get_next_run_number() - print(rn) - except Exception as e: - print(e) - - -callbacks_start_scan = [] -callbacks_start_scan = [lambda scan: namespace.init_all()] -callbacks_start_scan.append(_append_namespace_aliases_to_scan) -callbacks_start_scan.append(_append_namesace_status_to_scan) -callbacks_start_scan.append(_increment_daq_run_number) -callbacks_end_scan = [_message_end_scan] -callbacks_end_scan.append(_copy_scan_info_to_raw) - - -# >>>> Extract for run_table and elog - - -# if self._run_table or self._elog: -def _create_metadata_structure_start_scan(scan, run_table=run_table, elog=elog): - runname = os.path.basename(scan.fina).split(".")[0] - runno = int(runname.split("run")[1].split("_")[0]) - metadata = { - "type": "scan", - "name": runname.split("_", 1)[1], - "scan_info_file": scan.scan_info_filename, - } - for n, adj in enumerate(scan.adjustables): - nname = None - nId = None - if hasattr(adj, "Id"): - nId = adj.Id - if hasattr(adj, "name"): - nname = adj.name - - metadata.update( - { - f"scan_motor_{n}": nname, - f"from_motor_{n}": scan.values_todo[0][n], - f"to_motor_{n}": scan.values_todo[-1][n], - f"id_motor_{n}": nId, - } - ) - metadata.update( - { - "steps": len(scan.values_todo), - "pulses_per_step": scan.pulses_per_step, - "counters": [daq.name for daq in scan.counterCallers], - } - ) - - try: - try: - metadata.update({"scan_command": get_ipython().user_ns["In"][-1]}) - except: - print("Count not retrieve ipython scan command!") - - message_string = f'Acquisition run {runno}: {metadata["name"]}\n' - if "scan_command" in metadata.keys(): - message_string += metadata["scan_command"] + "\n" - message_string += metadata["scan_info_file"] + "\n" - scan._elog_id = elog.post( - message_string, Title=f'Run {runno}: {metadata["name"]}' - ) - metadata.update({"elog_message_id": scan._elog_id}) - metadata.update({"elog_post_link": scan._elog._log._url + str(scan._elog_id)}) - except: - print("elog posting failed") - try: - run_table.append_run(runno, metadata=metadata) - except: - print("WARNING: issue adding data to run table") - - -# <<<< Extract for run table and elog -callbacks_start_scan.append(_create_metadata_structure_start_scan) - - -namespace.append_obj( - "Scans", - data_base_dir="scan_data", - scan_info_dir=f"/sf/bernina/data/{config_bernina.pgroup()}/res/scan_info", - default_counters=[daq], - checker=checker, - scan_directories=True, - callbacks_start_scan=callbacks_start_scan, - callbacks_end_scan=callbacks_end_scan, - run_table=run_table, - elog=elog, - name="scans", - module_name="eco.acquisition.scan", - lazy=True, -) - - -##################################################################################################### -## more temporary devices will be outcoupled to temorary module. -# namespace.append_obj( -# "RIXS", -# lazy=True, -# name="rixs", -# module_name="eco.endstations.bernina_rixs", -# ) - -#### Beam pointing cameras for THz setups #### - - -# namespace.append_obj( -# "CameraBasler", -# pvname="SLAAR21-LCAM-C531", -# lazy=True, -# name="cam_NIR_position", -# camserver_group=["Laser", "Bernina"], -# module_name="eco.devices_general.cameras_swissfel", -# ) -# -# -# namespace.append_obj( -# "CameraBasler", -# pvname="SLAAR21-LCAM-C511", -# lazy=True, -# name="cam_NIR_angle", -# camserver_group=["Laser", "Bernina"], -# module_name="eco.devices_general.cameras_swissfel", -# ) - -namespace.append_obj( - "AxisPTZ", - "bernina-cam-mobile1", - lazy=True, - name="cam_mob1", - module_name="eco.devices_general.cameras_ptz", -) - -namespace.append_obj( - "BerninaInlineMicroscope", - pvname_camera="SARES20-CAMS142-M3", - lazy=True, - name="samplecam_inline", - module_name="eco.microscopes", -) - -# namespace.append_obj( -# "MicroscopeMotorRecord", -# pvname_camera="SARES20-CAMS142-C1", -# lazy=True, -# name="samplecam", -# module_name="eco.microscopes", -# pvname_zoom="SARES20-MF1:MOT_16", -# ) - -namespace.append_obj( - "MicroscopeMotorRecord", - "SARES20-CAMS142-C1", - lazy=True, - pvname_zoom="SARES20-MF1:MOT_16", - name="samplecam_microscope", - module_name="eco.microscopes", -) - -namespace.append_obj( - "CameraBasler", - "SARES20-CAMS142-C2", - lazy=True, - name="samplecam_sideview", - module_name="eco.devices_general.cameras_swissfel", -) - -namespace.append_obj( - "CameraBasler", - "SARES20-CAMS142-C3", - lazy=True, - name="samplecam_xrd", - module_name="eco.devices_general.cameras_swissfel", -) - -# namespace.append_obj( -# "PaseShifterAramis", -# "SLAAR02-TSPL-EPL", -# lazy=True, -# name="phase_shifter", -# module_name="eco.devices_general.timing", -# ) - - -# will be split in permanent and temporary -# namespace.append_obj( -# "Laser_Exp", -# lazy=True, -# name="las", -# module_name="eco.loptics.bernina_experiment", -# Id="SLAAR21-LMOT", -# smar_config=config_berninamesp["las_smar_config"], -# ) - -# new version -namespace.append_obj( - "LaserBernina", - "SLAAR21-LMOT", - lazy=True, - name="las", - module_name="eco.loptics.bernina_laser", -) -# namespace.append_obj( -# "IncouplingCleanBernina", -# lazy=False, -# name="las_inc", -# module_name="eco.loptics.bernina_laser", -# ) - - -from ..elements.assembly import Assembly -from ..devices_general.motors import SmaractStreamdevice - - -# namespace.append_obj( -# "Organic_crystal_breadboard", -# lazy=True, -# name="ocb", -# module_name="eco.endstations.bernina_sample_environments", -# Id="SARES23", -# ) - -from ..epics.adjustable import AdjustablePv - -# ad hoc N2 jet readout -class N2jet(Assembly): - def __init__(self, name=None): - super().__init__(name=name) - - ### lakeshore temperatures #### - self._append( - AdjustablePv, - pvsetname="SARES20-CRYO:TEMP-C_RBV", - pvreadbackname="SARES20-CRYO:TEMP-C_RBV", - accuracy=0.1, - name="sample_temp", - is_setting=False, - ) - ### oxford jet readouts #### - self._append( - AdjustablePv, - pvsetname="SARES20-OXCS:GasSetPoint", - pvreadbackname="SARES20-OXCS:GasSetPoint", - accuracy=0.1, - name="gas_temp_setpoint", - is_setting=False, - ) - self._append( - AdjustablePv, - pvsetname="SARES20-OXCS:GasTemp", - pvreadbackname="SARES20-OXCS:GasTemp", - accuracy=0.1, - name="gas_temp", - is_setting=False, - ) - self._append( - AdjustablePv, - pvsetname="SARES20-OXCS:GasFlow", - pvreadbackname="SARES20-OXCS:GasFlow", - accuracy=0.1, - name="gas_flow", - is_setting=False, - ) - self._append( - AdjustablePv, - pvsetname="SARES20-OXCS:Remaining", - pvreadbackname="SARES20-OXCS:Remaining", - accuracy=0.1, - name="gas_remaining", - is_setting=False, - ) - - -namespace.append_obj( - N2jet, - lazy=True, - name="jet", -) - -# ad hoc incoupling device -class Incoupling(Assembly): - def __init__(self, name=None): - super().__init__(name=name) - self._append( - SmaractRecord, "SARES23:LIC13", name="mirr_table_pitch", is_setting=True - ) - self._append( - SmaractRecord, "SARES23:LIC14", name="mirr_table_roll", is_setting=True - ) - # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) - # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) - # self._append(SmaractRecord, "SARES23:ESB17", name="rotation", is_setting=True) - - -namespace.append_obj( - Incoupling, - lazy=True, - name="las_inc", -) - - -namespace.append_obj( - "SmaractController", - "SARES23:LIC", - lazy=True, - name="smaract_ust", - module_name="eco.motion.smaract", -) - -namespace.append_obj( - "SmaractController", - "SARES23:ESB", - lazy=True, - name="smaract_user", - module_name="eco.motion.smaract", -) - - -from ..devices_general.motors import MotorRecord -from ..loptics.bernina_laser import DelayTime -from ..microscopes import MicroscopeMotorRecord - - -class JohannAnalyzer(Assembly): - def __init__(self, name=""): - super().__init__(name=name) - self._append( - MotorRecord, - "SARES20-MF1:MOT_3", - name="pitch", - is_setting=True, - is_display=True, - ) - self._append( - MotorRecord, - "SARES20-MF1:MOT_4", - name="roll", - is_setting=True, - is_display=True, - ) - - -namespace.append_obj(JohannAnalyzer, name="analyzer") - -# ad hoc 2 pulse setup -# class Laser2pulse(Assembly): -# def __init__(self, name=None): -# super().__init__(name=name) -# self._append( -# SmaractStreamdevice, -# "SARES23-ESB1", -# name="pump_exp_delaystage", -# is_setting=True, -# ) -# -# self._append( -# DelayTime, -# self.pump_exp_delaystage, -# name="pump_delay_exp", -# is_setting=False, -# is_display=True, -# reset_current_value_to=False, -# ) -# self._append(SmaractStreamdevice, "SARES23-ESB5", name="wp", is_setting=True) -# self._append( -# SmaractStreamdevice, -# "SARES23-ESB4", -# name="pump_2_delaystage", -# is_setting=True, -# ) -# self._append( -# DelayTime, -# self.pump_2_delaystage, -# name="pump_2_delay", -# is_setting=False, -# is_display=True, -# reset_current_value_to=False, -# ) -# self._append(SmaractStreamdevice, "SARES23-ESB6", name="ratio", is_setting=True) -# self._append( -# SmaractStreamdevice, "SARES23-ESB17", name="rx_pump", is_setting=True -# ) -# self._append( -# SmaractStreamdevice, "SARES23-ESB18", name="ry_pump", is_setting=True -# ) -# -# -# namespace.append_obj( -# Laser2pulse, -# lazy=True, -# name="laser2pulse", -# ) - - -# from eco.xoptics import dcm_pathlength_compensation as dpc -# namespace.append_obj( -# "MonoTimecompensation", -# # laser2pulse.pump_delay_exp, -# las.delay_glob, -# mono, -# "/sf/bernina/config/eco/reference_values/dcm_reference_timing.json", -# "/sf/bernina/config/eco/reference_values/dcm_reference_invert_delay.json", -# lazy=True, -# name="mono_time_corrected", -# module_name="eco.xoptics.dcm_pathlength_compensation", -# ) - - -# ad hoc interferometric timetool -# class TTinterferometrid(Assembly): -# def __init__(self, name=None): -# super().__init__(name=name) -# self._append(MotorRecord, "SARES20-MF1:MOT_7", name="z_target", is_setting=True) -# self._append( -# MotorRecord, "SARES20-MF1:MOT_10", name="x_target", is_setting=True -# ) -# self._append( -# MotorRecord, -# "SLAAR21-LMOT-M521:MOTOR_1", -# name="delaystage", -# is_setting=True -# # MotorRecord,"SLAAR21-LMOT-M521",name = "" -# # starting following commandline silently: -# # caqtdm -macro "P=SLAAR21-LMOT-M521:,M=MOTOR_1" motorx_more.ui -# ) -# self._append( -# DelayTime, -# self.delaystage, -# name="delay", -# is_setting=True, -# is_display=True, -# ) -# self._append( -# SmaractStreamdevice, -# "SARES23-ESB18", -# name="rot_BC", -# accuracy=3e-3, -# is_setting=True, -# ) -# # self._append( -# # MotorRecord, "SARES20-MF1:MOT_15", name="zoom_microscope", is_setting=True -# # ) -# self._append( -# MicroscopeMotorRecord, -# pvname_camera="SARES20-CAMS142-M1", -# camserver_alias="tt_spatial", -# pvname_zoom="SARES20-MF1:MOT_15", -# is_setting=True, -# is_display="recursive", -# name="microscope", -# ) -# -# -# namespace.append_obj( -# TTinterferometrid, -# lazy=True, -# name="exp", -# ) - - -############## experiment specific ############# - -# try to append pgroup folder to path !!!!! This caused eco to run in a timeout without error traceback !!!!! -try: - - import sys - from ..utilities import TimeoutPath - - if TimeoutPath(f"/sf/bernina/data/{config_bernina.pgroup()}/res/").exists(): - pgroup_eco_path = TimeoutPath( - f"/sf/bernina/data/{config_bernina.pgroup()}/res/eco" - ) - pgroup_eco_path.mkdir(mode=775, exist_ok=True) - sys.path.append(pgroup_eco_path.as_posix()) - else: - print( - "Could not access experiment folder, could be due to more systematic file system failure!" - ) -except: - print("Did not succed to append an eco folder in current prgoup") - - -#### pgroup specific appending, might be temporary at this location #### - -# namespace.append_obj("Xom", module_name="xom", name="xom", lazy=True) - - -############## maybe to be recycled ################### - -# { -# "args": [], -# "name": "ocb", -# "z_und": 142, -# "desc": "LiNbO3 crystal breadboard", -# "type": "eco.endstations.bernina_sample_environments:LiNbO3_crystal_breadboard", -# "kwargs": {"Id": "SARES23"}, -# }, -# { -# "args": [], -# "name": "vonHamos", -# "z_und": 142, -# "desc": "Kern experiment, von Hamos vertical and horizontal stages ", -# "type": "eco.devices_general.micos_stage:stage", -# "kwargs": { -# "vonHamos_horiz_pv": config["Kern"]["vonHamos_horiz"], -# "vonHamos_vert_pv": config["Kern"]["vonHamos_vert"], -# }, -# }, - -# { -# "name": "mono_old", -# "args": ["SAROP21-ODCM098"], -# "kwargs": { -# "energy_sp": "SAROP21-ARAMIS:ENERGY_SP", -# "energy_rb": "SAROP21-ARAMIS:ENERGY", -# }, -# "z_und": 98, -# "desc": "DCM Monochromator", -# "type": "eco.xoptics.dcm:Double_Crystal_Mono", -# }, diff --git a/eco/dummy/config.py b/eco/dummy/config.py deleted file mode 100755 index f818f54..0000000 --- a/eco/dummy/config.py +++ /dev/null @@ -1,655 +0,0 @@ -# # New configuration of components: -# components is an ordered list of -# - name in parent package -# - type, describing the python Class or factory function. -# - arguments of that type args -# - kwargs of that type - -# # Conventions for the type -# the call of type will try to pass a kwarg 'name' with the -# name of the component, before only calling args and kwargs. -# if arg or kwarg is of type eco.utilities.Component (dummy class) -# this indicates that an earlier initialized object is used -# (e.g. from same configuration). -from ..utilities.config import ( - Component, - init_device, - initFromConfigList, - Configuration, -) - -_eco_lazy_init = False - -config = Configuration( - "/sf/bernina/config/eco/bernina_config_eco.json", name="bernina_config" -) - -components = [ - { - "type": "eco.utilities.config:append_to_path", - "args": config["path_exp"], - "name": "path_exp", - "kwargs": {}, - "lazy": True, - }, - { - "name": "elog", - "type": "eco.utilities.elog:Elog", - "args": ["https://elog-gfa.psi.ch/Bernina"], - "kwargs": { - "screenshot_directory": "/tmp", - }, - }, - { - "name": "screenshot", - "type": "eco.utilities.elog:Screenshot", - "args": [], - "kwargs": {"screenshot_directory": "/sf/bernina/config/screenshots"}, - }, - { - "name": "fel", - "type": "eco.fel.swissfel:SwissFel", - "args": [], - "kwargs": {}, - "desc": "Fel related control and feedback", - }, - # { - # "name": "slit_und", - # "type": "eco.xoptics.slits:SlitFourBlades_old", - # "args": ["SARFE10-OAPU044"], - # "kwargs": {}, - # "desc": "Slit after Undulator", - # }, - # { - # "name": "slit_und_epics", - # "type": "eco.xoptics.slits:SlitFourBlades_old", - # "args": ["SARFE10-OAPU044"], - # "kwargs": {}, - # "desc": "Slit after Undulator", - # }, - # { - # "name": "mon_und", - # "args": ["SARFE10-PBPS053"], - # "z_und": 53, - # "desc": "Intensity/Position monitor after Undolator", - # "type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS", - # "kwargs": {"VME_crate": "SAROP21-CVME-PBPS2", "link": 9}, - # }, - { - "name": "mon_und", - "z_und": 53, - "desc": "Intensity/position monitor after Undulator", - "type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS_new", - "args": ["SARFE10-PBPS053"], - "kwargs": { - "VME_crate": "SAROP21-CVME-PBPS1", - "link": 9, - "channels": { - "up": "SLAAR21-LSCP1-FNS:CH6:VAL_GET", - "down": "SLAAR21-LSCP1-FNS:CH7:VAL_GET", - "left": "SLAAR21-LSCP1-FNS:CH4:VAL_GET", - "right": "SLAAR21-LSCP1-FNS:CH5:VAL_GET", - }, - "calc": { - "itot": "SLAAR21-LTIM01-EVR0:CALCI", - "xpos": "SLAAR21-LTIM01-EVR0:CALCX", - "ypos": "SLAAR21-LTIM01-EVR0:CALCY", - }, - }, - }, - { - "name": "pshut_und", - "type": "eco.xoptics.shutters:PhotonShutter", - "args": ["SARFE10-OPSH044:REQUEST"], - "kwargs": {}, - "z_und": 44, - "desc": "First shutter after Undulators", - }, - { - "name": "pshut_fe", - "type": "eco.xoptics.shutters:PhotonShutter", - "args": ["SARFE10-OPSH059:REQUEST"], - "kwargs": {}, - "z_und": 59, - "desc": "Photon shutter end of front end", - }, - { - "name": "sshut_opt", - "type": "eco.xoptics.shutters:SafetyShutter", - "args": ["SGE01-EPKT822:BST1_oeffnen"], - "kwargs": {}, - "z_und": 115, - "desc": "Bernina safety shutter", - }, - { - "name": "sshut_fe", - "type": "eco.xoptics.shutters:SafetyShutter", - "args": ["SGE01-EPKT820:BST1_oeffnen"], - "kwargs": {}, - "z_und": 115, - "desc": "Bernina safety shutter", - }, - { - "name": "att_fe", - "type": "eco.xoptics.attenuator_aramis:AttenuatorAramis", - "args": ["SARFE10-OATT053"], - "kwargs": {"shutter": Component("pshut_und")}, - "z_und": 53, - "desc": "Attenuator in Front End", - }, - # { - # "name": "mon_und", - # "z_und": 53, - # "desc": "Intensity/position monitor after Optics hutch", - # "type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS", - # "args": ["SARFE10-PBPS053"], - # "kwargs": {}, - # }, - { - "name": "xspect", - "z_und": 53, - "desc": "X-ray single shot spectrometer", - "type": "eco.xdiagnostics.xspect:Xspect", - "args": [], - "kwargs": {}, - }, - { - "name": "prof_fe", - "args": ["SARFE10-PPRM064"] * 2, - "kwargs": {}, - "z_und": 64, - "desc": "Profile monitor after Front End", - "type": "eco.xdiagnostics.profile_monitors:Pprm", - }, - { - "name": "prof_mirr_alv1", - "args": ["SAROP11-PPRM066"] * 2, - "kwargs": {}, - "z_und": 66, - "desc": "Profile monitor after Alvra Mirror 1", - "type": "eco.xdiagnostics.profile_monitors:Pprm", - }, - { - "name": "prof_mirr1", - "args": ["SAROP21-PPRM094"] * 2, - "kwargs": {}, - "z_und": 94, - "desc": "Profile monitor after Mirror 1", - "type": "eco.xdiagnostics.profile_monitors:Pprm", - }, - { - "name": "offset", - "args": [], - "kwargs": {}, - "z_und": 96, - "desc": "offset mirrors in pink mode", - "type": "eco.xoptics.offsetMirrors_new:OffsetMirrorsBernina", - "kwargs": {}, - }, - { - "name": "mono", - "args": ["SAROP21-ODCM098"], - "kwargs": {}, - "z_und": 98, - "desc": "DCM Monochromator", - "type": "eco.xoptics.dcm_new:DoubleCrystalMono", - }, - { - "name": "mono_old", - "args": ["SAROP21-ODCM098"], - "kwargs": { - "energy_sp": "SAROP21-ARAMIS:ENERGY_SP", - "energy_rb": "SAROP21-ARAMIS:ENERGY", - }, - "z_und": 98, - "desc": "DCM Monochromator", - "type": "eco.xoptics.dcm:Double_Crystal_Mono", - }, - { - "name": "prof_mono", - "args": ["SAROP21-PPRM113"] * 2, - "kwargs": {}, - "z_und": 102, - "desc": "Profile monitor after Monochromator", - "type": "eco.xdiagnostics.profile_monitors:Pprm", - }, - { - "name": "xp", - "args": [], - "kwargs": { - "Id": "SAROP21-OPPI113", - "evronoff": "SGE-CPCW-72-EVR0:FrontUnivOut15-Ena-SP", - "evrsrc": "SGE-CPCW-72-EVR0:FrontUnivOut15-Src-SP", - }, - "z_und": 103, - "desc": "X-ray pulse picker", - "type": "eco.xoptics.pp:Pulsepick", - }, - # { - # "name": "mon_opt_old", - # "z_und": 133, - # "desc": "Intensity/position monitor after Optics hutch", - # "type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS", - # "args": ["SAROP21-PBPS133"], - # "kwargs": {"VME_crate": "SAROP21-CVME-PBPS1", "link": 9}, - # }, - { - "name": "mon_opt", - "z_und": 133, - "desc": "Intensity/position monitor after Optics hutch", - "type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS_new", - "args": ["SAROP21-PBPS133"], - "kwargs": { - "VME_crate": "SAROP21-CVME-PBPS1", - "link": 9, - "channels": { - "up": "SLAAR21-LSCP1-FNS:CH6:VAL_GET", - "down": "SLAAR21-LSCP1-FNS:CH7:VAL_GET", - "left": "SLAAR21-LSCP1-FNS:CH4:VAL_GET", - "right": "SLAAR21-LSCP1-FNS:CH5:VAL_GET", - }, - "calc": { - "itot": "SLAAR21-LTIM01-EVR0:CALCI", - "xpos": "SLAAR21-LTIM01-EVR0:CALCX", - "ypos": "SLAAR21-LTIM01-EVR0:CALCY", - }, - }, - }, - { - "name": "prof_opt", - "args": ["SAROP21-PPRM133"] * 2, - "kwargs": {}, - "z_und": 133, - "desc": "Profile monitor after Optics hutch", - "type": "eco.xdiagnostics.profile_monitors:Pprm", - }, - { - "name": "spect_tt", - "args": ["SAROP21-PSEN135"], - "kwargs": {"reduction_client_address": "http://sf-daqsync-01:8889/"}, - "z_und": 135, - "desc": "Spectral encoding timing diagnostics before Attenuator.", - "type": "eco.xdiagnostics.timetools:SpectralEncoder", - }, - { - "name": "att", - "args": ["SAROP21-OATT135"], - "kwargs": {"shutter": Component("xp"), "set_limits": []}, - "z_und": 135, - "desc": "Attenuator Bernina", - "type": "eco.xoptics.attenuator_aramis:AttenuatorAramis", - }, - # { - # "name": "slit_att", - # "args": ["SAROP21-OAPU136"], - # "kwargs": {}, - # "z_und": 136, - # "desc": "Slits behind attenuator", - # "type": "eco.xoptics.slits:SlitPosWidth", - # }, - { - "name": "det_dio", - "args": ["SAROP21-PDIO138"], - "z_und": 138, - "desc": "Diode digitizer for exp data", - "type": "eco.devices_general.detectors:DiodeDigitizer", - "kwargs": {"VME_crate": "SAROP21-CVME-PBPS2", "link": 9}, - }, - { - "name": "prof_att", - "args": ["SAROP21-PPRM138"] * 2, - "kwargs": {}, - "z_und": 138, - "desc": "Profile monitor after Attenuator", - "type": "eco.xdiagnostics.profile_monitors:Pprm", - }, - # { - # "name": "spatial_tt", - # "args": [], - # "kwargs": {"reduction_client_address": "http://sf-daqsync-02:12003/"}, - # "z_und": 141, - # "desc": "spatial encoding timing diagnostics before sample.", - # "type": "eco.xdiagnostics.timetools:SpatialEncoder", - # "lazy": True, - # }, - # { - # "name": "slit_kb", - # "args": [], - # "kwargs": {"pvname": "SARES20-MF1"}, - # "z_und": 141, - # "desc": "Slits behind Kb", - # "type": "eco.xoptics.slits:SlitBlades_JJ", - # # "type": "eco.xoptics.slits:SlitBladesJJ_old", - # }, - # { - # "args": [], - # "name": "gps_old", - # "z_und": 142, - # "desc": "General purpose station", - # "type": "eco.endstations.bernina_diffractometers:GPS_old", - # "kwargs": { - # "Id": "SARES22-GPS", - # "configuration": config["gps_config"], - # "fina_hex_angle_offset": "/sf/bernina/config/eco/reference_values/hex_pi_angle_offset.json", - # }, - # "lazy": True, - # }, - # { - # "args": [], - # "name": "xrd_old", - # "z_und": 142, - # "desc": "Xray diffractometer", - # "type": "eco.endstations.bernina_diffractometers:XRD_old", - # "kwargs": {"Id": "SARES21-XRD", "configuration": config["xrd_config"]}, - # }, - # { - # "args": [], - # "name": "xrd", - # "z_und": 142, - # "desc": "Xray diffractometer", - # "type": "eco.endstations.bernina_diffractometers:XRD", - # "kwargs": { - # "Id": "SARES21-XRD", - # "configuration": config["xrd_config"], - # "diff_detector": {"jf_id": "JF01T03V01"}, - # }, - # }, - { - "args": [], - "name": "vonHamos", - "z_und": 142, - "desc": "Kern experiment, von Hamos vertical and horizontal stages ", - "type": "eco.devices_general.micos_stage:stage", - "kwargs": { - "vonHamos_horiz_pv": config["Kern"]["vonHamos_horiz"], - "vonHamos_vert_pv": config["Kern"]["vonHamos_vert"], - }, - }, - # { - # "args": [], - # "name": "gasjet", - # "z_und": 142, - # "desc": "ToF comm. gasjet", - # "type": "tof:jet", - # "kwargs": {}, - # }, - { - "args": ["SARES20-CAMS142-M1"], - "name": "cam_sample_sideview", - "z_und": 142, - "desc": "", - "type": "eco.devices_general.cameras_swissfel:CameraBasler", - "kwargs": {}, - }, - { - "args": ["SARES20-CAMS142-M3"], - "name": "cam_sample_inline", - "z_und": 142, - "desc": "", - "type": "eco.devices_general.cameras_swissfel:CameraBasler", - "kwargs": {}, - }, - # { - # "args": ["SARES20-CAMS142-C3"], - # "name": "cam_sample_xrd", - # "z_und": 142, - # "desc": "", - # "type": "eco.devices_general.cameras_swissfel:CameraBasler", - # "kwargs": {}, - # }, - # { - # "args": [], - # "name": "cams_qioptiq", - # "z_und": 142, - # "desc": "Qioptic sample viewer in Bernina hutch", - # "type": "eco.endstations.bernina_cameras:Qioptiq", - # "kwargs": { - # "bshost": "sf-daqsync-01.psi.ch", - # "bsport": 11149, - # "zoomstage_pv": config["cams_qioptiq"]["zoomstage_pv"], - # "camera_pv": config["cams_qioptiq"]["camera_pv"], - # }, - # }, - { - "args": [], - "name": "cams_sigma", - "z_und": 142, - "desc": "Sigma objective", - "type": "eco.endstations.bernina_cameras:Sigma", - "kwargs": { - "bshost": "sf-daqsync-01.psi.ch", - "bsport": 11149, - "camera_pv": config["cams_sigma"]["camera_pv"], - }, - }, - # { - # "args": ["SLAAR02-TSPL-EPL"], - # "name": "phase_shifter", - # "z_und": 142, - # "desc": "Experiment laser phase shifter", - # "type": "eco.devices_general.timing:PhaseShifterAramis", - # "kwargs": {}, - # }, - { - "args": ["SLAAR21-LTIM01-EVR0"], - "name": "laser_shutter", - "z_und": 142, - "desc": "Laser Shutter", - "type": "eco.loptics.laser_shutter:laser_shutter", - "kwargs": {}, - }, - { - "args": [], - "name": "epics_channel_list", - "desc": "epics channel list", - "type": "eco.utilities.config:ChannelList", - "kwargs": { - "file_name": "/sf/bernina/config/channel_lists/default_channel_list_epics" - }, - "lazy": True, - }, - { - "args": [], - "name": "epics_daq", - "z_und": 142, - "desc": "epics data acquisition", - "type": "eco.acquisition.epics_data:Epicstools", - "kwargs": { - "channel_list": Component("epics_channel_list"), - "default_file_path": f"/sf/bernina/data/{config['pgroup']}/res/epics_daq/", - }, - "lazy": True, - }, - # { - # "args": [], - # "name": "daq_dia_old", - # "desc": "server based acquisition", - # "type": "eco.acquisition.dia:DIAClient", - # "kwargs": { - # "instrument": "bernina", - # "api_address": config["daq_address"], - # "pgroup": config["pgroup"], - # "pedestal_directory": config["jf_pedestal_directory"], - # "gain_path": config["jf_gain_path"], - # "config_default": config["daq_dia_config"], - # "jf_channels": config["jf_channels"], - # "default_file_path": None, - # }, - # }, - { - "args": [ - config["checker_PV"], - config["checker_thresholds"], - config["checker_fractionInThreshold"], - ], #'SARFE10-PBPG050:HAMP-INTENSITY-CAL',[60,700],.7], - "name": "checker", - "desc": "checker functions for data acquisition", - "type": "eco.acquisition.checkers:CheckerCA", - "kwargs": {}, - }, - # { - # "args": [ - # "SARES20-LSCP9-FNS:CH1:VAL_GET", - # [-100000, 100000], - # config["checker_fractionInThreshold"], - # ], #'SARFE10-PBPG050:HAMP-INTENSITY-CAL',[60,700],.7], - # "name": "checker_epics", - # "desc": "checker functions for data acquisition", - # "type": "eco.acquisition.checkers:CheckerCA", - # "kwargs": {}, - # }, - # { - # "args": [], - # "name": "scans_epics", - # "desc": "epics non beam synchronous based acquisition", - # "type": "eco.acquisition.scan:Scans", - # "kwargs": { - # "data_base_dir": "scan_data", - # "scan_info_dir": f"/sf/bernina/data/{config['pgroup']}/res/scan_info", - # "default_counters": [Component("epics_daq")], - # "checker": Component("checker_epics"), - # "scan_directories": True, - # "run_table": Component("run_table"), - # }, - # "lazy": True, - # }, - # { - # "args": [], - # "name": "lxt", - # "desc": "laser timing with pockels cells and phase shifter", - # "type": "eco.timing.lasertiming:Lxt", - # "kwargs": {}, - # }, - # { - # "args": ["SARES20-CVME-01-EVR0"], - # "name": "evr_bernina", - # "desc": "Bernina event receiver", - # "type": "eco.timing.event_timing:EventReceiver", - # "kwargs": {}, - # }, - { - "args": [], - "name": "default_channel_list", - "desc": "Bernina default channels, used in daq", - "type": "eco.utilities.config:ChannelList", - "kwargs": { - "file_name": "/sf/bernina/config/channel_lists/default_channel_list" - }, - }, - { - "args": [], - "name": "default_channel_list_bs", - "desc": "Bernina default bs channels, used by bs_daq", - "type": "eco.utilities.config:ChannelList", - "kwargs": { - "file_name": "/sf/bernina/config/channel_lists/default_channel_list_bs" - }, - }, - { - "args": [], - "name": "channels_spectrometer_projection", - "desc": "", - "type": "eco.utilities.config:ChannelList", - "kwargs": { - "file_name": "/sf/bernina/config/channel_lists/channel_list_PSSS_projection" - }, - }, - { - "args": [], - "name": "bs_daq", - "desc": "bs daq writer (locally!)", - "type": "eco.acquisition.bs_data:BStools", - "kwargs": { - "default_channel_list": { - "bernina_default_channels_bs": Component("default_channel_list_bs") - }, - "default_file_path": f"/sf/bernina/data/{config['pgroup']}/res/%s", - }, - }, - # { - # "args": ["SARES23-"], - # "name": "slit_kb", - # "z_und": 141, - # "desc": "Upstream diagnostics slits", - # "type": "eco.xoptics.slit_USD:Upstream_diagnostic_slits", - # "kwargs": {"right": "LIC4", "left": "LIC3", "up": "LIC2", "down": "LIC1"}, - # }, - # { - # "args": ["SARES23-"], - # "name": "slit_cleanup", - # "z_und": 141, - # "desc": "Upstream diagnostics slits", - # "type": "eco.xoptics.slit_USD:Upstream_diagnostic_slits", - # "kwargs": {"right": "LIC7", "left": "LIC8", "up": "LIC8", "down": "LIC5"}, - # }, - { - "args": [ - [ - Component("slit_und"), - Component("slit_switch"), - Component("slit_att"), - Component("slit_kb"), - ] - ], - "name": "slits", - "desc": "collection of all slits", - "type": "eco.utilities.beamline:Slits", - "kwargs": {}, - }, - # { - # "args": [ - # [Component("slit_switch"), Component("slit_att"), Component("slit_kb"),] - # ], - # "name": "slits", - # "desc": "collection of all slits", - # "type": "eco.utilities.beamline:Slits", - # "kwargs": {}, - # "lazy": False, - # }, - # { - # "args": [], - # "name": "thc", - # "z_und": 142, - # "desc": "High field THz Chamber", - # "type": "eco.endstations.bernina_sample_environments:High_field_thz_chamber", - # "kwargs": {"Id": "SARES23", "configuration": ["ottifant"]}, - # }, - # { - # "args": [], - # "name": "ocb", - # "z_und": 142, - # "desc": "Organic Crystal Breadboard", - # "type": "eco.endstations.bernina_sample_environments:Organic_crystal_breadboard", - # "kwargs": {"Id": "SARES23"}, - # }, - # { - # "args": [], - # "name": "eos", - # "z_und": 142, - # "desc": "electro optic sampling stages", - # "type": "eco.endstations.bernina_sample_environments:Electro_optic_sampling", - # "kwargs": { - # "Id": "SARES23", - # "pgroup": config["pgroup"], - # "diode_channels": { - # "d1": "SARES20-LSCP9-FNS:CH1:VAL_GET", - # "d2": "SARES20-LSCP9-FNS:CH2:VAL_GET", - # "diff": "SARES20-LSCP9-FNS:CH3:VAL_GET", - # }, - # }, - # }, - { - "args": [], - "name": "dsd", - "z_und": 146, - "desc": "downstream diagnostics", - "type": "eco.xdiagnostics.dsd:DownstreamDiagnostic", - "kwargs": {}, - }, -] - -try: - components.extend(config["components"]) - print("Did append additional components!") -except: - print("Could not append components from config.") diff --git a/eco/dummy/dummy.py b/eco/dummy/dummy.py deleted file mode 100644 index 99fa941..0000000 --- a/eco/dummy/dummy.py +++ /dev/null @@ -1,32 +0,0 @@ -from eco.elements.adjustable import AdjustableFS -from eco.motion.smaract import SmaractController - -# from .config import components -# from .config import config as config_berninamesp -from ..utilities.config import Namespace - -# from ..aliases import NamespaceCollection -import pyttsx3 - -from ..utilities.path_alias import PathAlias -import sys, os -from IPython import get_ipython - - -# path_aliases = PathAlias() -# sys.path.append("/sf/bernina/config/src/python/bernina_analysis") - -# namespace = Namespace( -# name="bernina", root_module=__name__, alias_namespace=NamespaceCollection().bernina -# ) -# namespace.alias_namespace.data = [] - -# # Adding stuff that might be relevant for stuff configured below (e.g. config) - -# _config_bernina_dict = AdjustableFS( -# "/sf/bernina/config/eco/configuration/bernina_config.json", -# name="_config_bernina_dict", -# ) -# from eco.elements.adj_obj import AdjustableObject - -# namespace.append_obj(AdjustableObject, _config_bernina_dict, name="config_bernina") diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index 4764729..cb0f4e2 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -178,16 +178,16 @@ class LaserBernina(Assembly): MotorRecord, self.pvname + "-M532:MOT", name="compressor", is_setting=True ) # Waveplate and Delay stage - # self._append( - # MotorRecord, self.pvname + "-M533:MOT", name="wp_pol", is_setting=True - # ) + self._append( + MotorRecord, self.pvname + "-M533:MOT", name="wp_pol", is_setting=True + ) - # self._append( - # MotorRecord, self.pvname + "-M534:MOT", name="wp_att", is_setting=True - # ) + self._append( + MotorRecord, self.pvname + "-M534:MOT", name="wp_att", is_setting=True + ) # ad hoc for 500nm setup - self._append(SmaractRecord, "SARES23:ESB3", name="wp_att", is_setting=True) + # self._append(SmaractRecord, "SARES23:ESB3", name="wp_att", is_setting=True) self._append( AdjustableFS, diff --git a/eco/utilities/config.py b/eco/utilities/config.py index cf83196..d54fb69 100644 --- a/eco/utilities/config.py +++ b/eco/utilities/config.py @@ -327,6 +327,7 @@ class Namespace(Assembly): N_cycles=4, silent=True, giveup_failed=True, + exclude_names=[], ): starttime = time() @@ -346,7 +347,7 @@ class Namespace(Assembly): self.exc_init.submit( self.init_name, name, verbose=verbose, raise_errors=raise_errors ) - for name in self.all_names + for name in (self.all_names - set(exclude_names)) ] self.exc_init.shutdown(wait=True) self.exc_init = ThreadPoolExecutor(max_workers=1) @@ -354,7 +355,9 @@ class Namespace(Assembly): self.exc_init.submit( self.init_name, name, verbose=verbose, raise_errors=raise_errors ) - for name in (self.all_names - self.initialized_names) + for name in ( + self.all_names - self.initialized_names - set(exclude_names) + ) ] self.exc_init.shutdown(wait=True) self.silently_initializing = False @@ -383,10 +386,12 @@ class Namespace(Assembly): lambda name: self.init_name( name, verbose=verbose, raise_errors=raise_errors ), - self.all_names - self.initialized_names, + self.all_names - self.initialized_names - exclude_names, ), description="Initializing ...", - total=len(self.all_names - self.initialized_names), + total=len( + self.all_names - self.initialized_names - exclude_names + ), transient=True, ) ) @@ -398,10 +403,12 @@ class Namespace(Assembly): lambda name: self.init_name( name, verbose=verbose, raise_errors=raise_errors ), - self.all_names - self.initialized_names, + self.all_names - self.initialized_names - exclude_names, ), description="Initializing ...", - total=len(self.all_names - self.initialized_names), + total=len( + self.all_names - self.initialized_names - exclude_names + ), transient=True, ) ) From b44b65a15c43889c032e0dc990d85c057e376993 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Tue, 28 Feb 2023 08:23:16 +0100 Subject: [PATCH 31/52] fixes --- eco/bernina/bernina.py | 2 +- eco/loptics/bernina_laser.py | 4 +- eco/utilities/config.py | 12 +- eco/utilities/recspace.py | 46 ++- eco/utilities/runtable.py | 710 ++--------------------------------- eco/xoptics/kb_bernina.py | 4 +- eco/xoptics/kb_mirrors.py | 33 ++ 7 files changed, 117 insertions(+), 694 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index b7df8ed..3eae5b2 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -1516,7 +1516,7 @@ class N2jet(Assembly): class Incoupling(Assembly): def __init__(self, name=None): super().__init__(name=name) - self._append(SmaractRecord, "SARES23:ESB10", name="pitch", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB11", name="pitch", is_setting=True) self._append(SmaractRecord, "SARES23:ESB13", name="roll", is_setting=True) # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index cb0f4e2..a5091bb 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -246,8 +246,8 @@ class LaserBernina(Assembly): # is_setting=True, # ) self._append( - SmaractRecord, - "SARES23:ESB1", + MotorRecord, + "SLAAR21-LMOT-M521:MOTOR_1", name="delaystage_pump", is_setting=True, ) diff --git a/eco/utilities/config.py b/eco/utilities/config.py index d54fb69..677ef8d 100644 --- a/eco/utilities/config.py +++ b/eco/utilities/config.py @@ -386,11 +386,13 @@ class Namespace(Assembly): lambda name: self.init_name( name, verbose=verbose, raise_errors=raise_errors ), - self.all_names - self.initialized_names - exclude_names, + self.all_names + - self.initialized_names + - set(exclude_names), ), description="Initializing ...", total=len( - self.all_names - self.initialized_names - exclude_names + self.all_names - self.initialized_names - set(exclude_names) ), transient=True, ) @@ -403,11 +405,13 @@ class Namespace(Assembly): lambda name: self.init_name( name, verbose=verbose, raise_errors=raise_errors ), - self.all_names - self.initialized_names - exclude_names, + self.all_names + - self.initialized_names + - set(exclude_names), ), description="Initializing ...", total=len( - self.all_names - self.initialized_names - exclude_names + self.all_names - self.initialized_names - set(exclude_names) ), transient=True, ) diff --git a/eco/utilities/recspace.py b/eco/utilities/recspace.py index 760bb8a..ba981fb 100644 --- a/eco/utilities/recspace.py +++ b/eco/utilities/recspace.py @@ -50,10 +50,11 @@ class Crystals(Assembly): default_value={}, is_setting=True, ) - for key, date in self.crystal_list().items(): - self._append( - DiffGeometryYou, diffractometer_you=self.diffractometer, name=key - ) + for key, [date, active] in self.crystal_list().items(): + if active: + self._append( + DiffGeometryYou, diffractometer_you=self.diffractometer, name=key + ) def append_crystal(self, name=None): if name == None: @@ -74,7 +75,7 @@ class Crystals(Assembly): is_display=False, ) crystals = self.crystal_list() - crystals[name] = str(datetime.now()) + crystals[name] = [str(datetime.now()), 1] self.crystal_list.mv(crystals) self.__dict__[name].new_ub() @@ -106,6 +107,41 @@ class Crystals(Assembly): f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_{a}" ) + def activate_crystal(self): + crystals = self.crystal_list() + inactive_crystals = [k for k in crystals.keys() if crystals[k][1]==0] + idx = '' + input_message = "Select the crystal to activate:\n" + for index, crystal in enumerate(inactive_crystals): + input_message += f'{index:2}) {crystal:15}\n' + input_message += 'Your choice: ' + while idx not in range(len(inactive_crystals)): + idx = int(input(input_message)) + print(f'Selected crystal: {inactive_crystals[idx]}') + name = inactive_crystals[idx] + self._append( + DiffGeometryYou, diffractometer_you=self.diffractometer, name=name + ) + + + + def deactivate_crystal(self): + crystals = self.crystal_list() + active_crystals = [k for k in crystals.keys() if crystals[k][1]==1] + idx = '' + input_message = "Select the crystal to activate:\n" + for index, crystal in enumerate(active_crystals): + input_message += f'{index:2}) {crystal:15}\n' + input_message += 'Your choice: ' + while idx not in range(len(active_crystals)): + idx = int(input(input_message)) + print(f'Selected crystal: {active_crystals[idx]}') + name = active_crystals[idx] + meta = crystals[name] + meta[1] = 0 + crystals[name] = meta + self.crystal_list.mv(crystals) + removed = self.__dict__.pop(name) class DiffGeometryYou(Assembly): def __init__(self, diffractometer_you=None, name=None): diff --git a/eco/utilities/runtable.py b/eco/utilities/runtable.py index 030d952..98d6ce8 100644 --- a/eco/utilities/runtable.py +++ b/eco/utilities/runtable.py @@ -8,7 +8,7 @@ from subprocess import call warnings.simplefilter(action="ignore", category=pd.errors.PerformanceWarning) warnings.simplefilter(action="ignore", category=UserWarning) - +import timeit import os from pathlib import Path from epics import PV @@ -32,685 +32,6 @@ pd.options.display.width = None pd.set_option("display.float_format", lambda x: "%.5g" % x) -class Run_Table: - def __init__( - self, - pgroup=None, - devices=None, - channels_ca={"pulse_id": "SLAAR11-LTIM01-EVR0:RX-PULSEID"}, - name=None, - ): - - ### Load device and alias_namespace after init of other devices ### - devices = eco.__dict__[devices] - self.devices = devices - self.name = name - self.adj_df = DataFrame() - self.unit_df = DataFrame() - self.gspread_key_df = None - self.gspread_key_file_name = ( - f"/sf/bernina/config/src/python/gspread/gspread_keys" - ) - - self._channels_ca = channels_ca - - ### credentials and settings for uploading to gspread ### - self._scope = [ - "https://spreadsheets.google.com/feeds", - "https://www.googleapis.com/auth/drive", - ] - self._credentials = ServiceAccountCredentials.from_json_keyfile_name( - "/sf/bernina/config/src/python/gspread/pandas_push", self._scope - ) - self.gc = gspread.authorize(self._credentials) - self.keys = "metadata midir xrd energy transmission delay lxt pulse_id att_self att_fe_self" - self.key_order = "metadata xrd midir env_thc temperature1_rbk temperature2_rbk time name gps gps_hex thc ocb eos las lxt phase_shifter mono att att_fe slit_und slit_switch slit_att slit_kb slit_cleanup pulse_id mono_energy_rbk att_transmission att_fe_transmission" - spreadsheet_key = (None,) - self.init_runtable(pgroup) - - ### dicts holding adjustables and bad (not connected) adjustables ### - self.adjustables = {} - self.bad_adjustables = {} - self.units = {} - - ###parsing options - self._parse_exclude_keys = "status_indicators settings_collection status_indicators_collection presets memory _elog _currentChange _flags __ alias namespace daq scan evr _motor Alias".split( - " " - ) - self._parse_exclude_class_types = ( - "__ alias namespace daq scan evr _motor Alias AdjustablePv AxisPTZ".split( - " " - ) - ) - self._adj_exclude_class_types = ( - "__ alias namespace daq scan evr _motor Alias".split(" ") - ) - - pd.options.display.max_rows = 100 - pd.options.display.max_columns = 50 - pd.set_option("display.float_format", lambda x: "%.5g" % x) - - def create_rt_spreadsheet(self, pgroup): - self.gc = gspread.authorize(self._credentials) - spreadsheet = self.gc.create( - title=f"run_table_{pgroup}", folder_id="1F7DgF0HW1O71nETpfrTvQ35lRZCs5GvH" - ) - spreadsheet.add_worksheet("runtable", 10, 10) - spreadsheet.add_worksheet("positions", 10, 10) - ws = spreadsheet.get_worksheet(0) - spreadsheet.del_worksheet(ws) - return spreadsheet - - def _append_to_gspread_key_df(self, gspread_key_df): - if os.path.exists(self.gspread_key_file_name + ".pkl"): - self.gspread_key_df = pd.read_pickle(self.gspread_key_file_name + ".pkl") - self.gspread_key_df = self.gspread_key_df.append(gspread_key_df) - self.gspread_key_df.to_pickle(self.gspread_key_file_name + ".pkl") - else: - self.gspread_key_df.to_pickle(self.gspread_key_file_name + ".pkl") - - def init_runtable(self, pgroup): - if os.path.exists(self.gspread_key_file_name + ".pkl"): - self.gspread_key_df = pd.read_pickle(self.gspread_key_file_name + ".pkl") - if self.gspread_key_df is not None and str(pgroup) in self.gspread_key_df.index: - spreadsheet_key = self.gspread_key_df["keys"][f"{pgroup}"] - else: - f_create = str( - input( - f"No google spreadsheet id found for pgroup {pgroup}. Create new run_table spreadsheet? (y/n) " - ) - ) - if f_create == "y": - print("creating") - spreadsheet = self.create_rt_spreadsheet(pgroup=pgroup) - print("created") - gspread_key_df = DataFrame( - {"keys": [spreadsheet.id]}, index=[f"{pgroup}"] - ) - spreadsheet_key = spreadsheet.id - else: - f_entermanually = input( - f"Do you want to enter a spreadsheet key for the pgroup {pgroup}? (y/n)" - ) - if f_entermanually != "y": - print("Runtable not initialized") - return - spreadsheet_key = str( - input( - f"Please enter the google spreadsheet key, e.g. 1gK--KePLpYCs7U3QfNSPo69XipndbINe1Iz8to9bY1U: " - ) - ) - gspread_key_df = DataFrame( - {"keys": [spreadsheet_key]}, index=[f"{pgroup}"] - ) - self._append_to_gspread_key_df(gspread_key_df) - self._spreadsheet_key = spreadsheet_key - # self.alias_file_name = ( - # f"/sf/bernina/data/{pgroup}/res/runtables/{pgroup}_alias_runtable" - # ) - self.adj_file_name = ( - f"/sf/bernina/data/{pgroup}/res/runtables/{pgroup}_adjustable_runtable" - ) - self.unit_file_name = ( - f"/sf/bernina/data/{pgroup}/res/runtables/{pgroup}_unit_runtable" - ) - self.load() - return - - def _query_by_keys(self, keys="", df=None): - if df is None: - df = self.adj_df - keys = keys.split(" ") - if len(df.columns[0]) > 1: - query_df = df[ - df.columns[ - np.array( - [ - np.any([np.any([x in i for x in keys]) for i in col]) - for col in df.columns - ] - ) - ] - ] - else: - query_df = df[ - df.columns[ - np.array([np.any([x in col for x in keys]) for col in df.columns]) - ] - ] - return query_df - - def query(self, keys="", index=None, values=None, df=None): - """ - function to show saved data. keys is a string with keys separated by a space. - All columns, which contain any of these strings are returned. self.prefix - + f"{runno:{self.Ndigits}0d}" - + self.separator - + "*." - + self.suffix - Index can be a list od indices. - - example: query(keys='xrd delay name', index = [0,5]) - will return all columns containing either xrd or delay and show the data for runs 0 and 5 - - example 2: query(keys = 'xrd delay name', index = ['p1', 'p2']) - will return the same columns for the saved positions 1 and 2 - """ - self.load() - # if len(keys) > 0: - # keys += " name" - query_df = self._query_by_keys(keys, df) - if not values is None: - query_df = query_df.query(values) - query_df = query_df.T - if not index is None: - query_df = query_df[index] - return query_df - - def _get_values(self): - is_connected = np.array([pv.connected for pv in self._pvs.values()]) - filtered_dict = {key: pv.value for key, pv in self._pvs.items() if pv.connected} - return filtered_dict - - def _remove_duplicates(self): - self.adj_df = self.adj_df[~self.adj_df.index.duplicated(keep="last")] - # self.alias_df = self.alias_df[~self.alias_df.index.duplicated(keep="last")] - self.unit_df = self.unit_df[~self.unit_df.index.duplicated(keep="last")] - - def save(self): - data_dir = Path(os.path.dirname(self.adj_file_name + ".pkl")) - if not data_dir.exists(): - print( - f"Path {data_dir.absolute().as_posix()} does not exist, will try to create it..." - ) - data_dir.mkdir(parents=True) - print(f"Tried to create {data_dir.absolute().as_posix()}") - data_dir.chmod(0o775) - print(f"Tried to change permissions to 775") - # self.alias_df.to_pickle(self.alias_file_name + ".pkl") - self.adj_df.to_pickle(self.adj_file_name + ".pkl") - self.unit_df.to_pickle(self.unit_file_name + ".pkl") - - def load(self): - # if os.path.exists(self.alias_file_name + ".pkl"): - # self.alias_df = pd.read_pickle(self.alias_file_name + ".pkl") - if os.path.exists(self.adj_file_name + ".pkl"): - self.adj_df = pd.read_pickle(self.adj_file_name + ".pkl") - if os.path.exists(self.unit_file_name + ".pkl"): - self.unit_df = pd.read_pickle(self.unit_file_name + ".pkl") - - def append_run( - self, - runno, - metadata={ - "type": "ascan", - "name": "phi scan (001)", - "scan_motor": "phi", - "from": 1, - "to": 2, - "steps": 51, - }, - ): - self.load() - if len(self.adjustables) == 0: - self._parse_parent_fewerparents() - # dat = self._get_values() - # dat.update(metadata) - # dat["time"] = datetime.now() - # run_df = DataFrame([dat.values()], columns=dat.keys(), index=[runno]) - # self.alias_df = self.alias_df.append(run_df) - - dat = self._get_adjustable_values() - dat["metadata"] = metadata - dat["metadata"]["time"] = datetime.now() - names = ["device", "adjustable"] - multiindex = pd.MultiIndex.from_tuples( - [(dev, adj) for dev in dat.keys() for adj in dat[dev].keys()], names=names - ) - values = np.array([val for adjs in dat.values() for val in adjs.values()]) - run_df = DataFrame([values], columns=multiindex, index=[runno]) - self.adj_df = self.adj_df.append(run_df) - multiindex_u = pd.MultiIndex.from_tuples( - [(dev, adj) for dev in self.units.keys() for adj in self.units[dev].keys()], - names=names, - ) - values_u = np.array( - [val for adjs in self.units.values() for val in adjs.values()] - ) - self.unit_df = DataFrame([values_u], columns=multiindex_u, index=["units"]) - self._remove_duplicates() - self.save() - self.upload_all() - - def append_pos(self, name=""): - self.load() - if len(self.adjustables) == 0: - self._parse_parent_fewerparents() - try: - posno = int(self.adj_df.query('type == "pos"').index[-1].split("p")[1]) + 1 - except: - posno = 0 - # dat = self._get_values() - # dat.update([("name", name), ("type", "pos")]) - # dat["time"] = datetime.now() - # pos_df = DataFrame([dat.values()], columns=dat.keys(), index=[f"p{posno}"]) - # self.alias_df = self.alias_df.append(pos_df) - - dat = self._get_adjustable_values() - dat["metadata"] = {"time": datetime.now(), "name": name, "type": "pos"} - names = ["device", "adjustable"] - multiindex = pd.MultiIndex.from_tuples( - [(dev, adj) for dev in dat.keys() for adj in dat[dev].keys()], names=names - ) - values = np.array([val for adjs in dat.values() for val in adjs.values()]) - pos_df = DataFrame([values], columns=multiindex, index=[f"p{posno}"]) - self.adj_df = self.adj_df.append(pos_df) - multiindex_u = pd.MultiIndex.from_tuples( - [(dev, adj) for dev in self.units.keys() for adj in self.units[dev].keys()], - names=names, - ) - values_u = np.array( - [val for adjs in self.units.values() for val in adjs.values()] - ) - self.unit_df = DataFrame([values_u], columns=multiindex_u, index=["units"]) - self.save() - self.upload_all() - - def upload_rt(self, worksheet="runtable", keys=None, df=None): - """ - This function uploads all entries of which "type" contains "scan" to the worksheet positions. - keys takes a string of keys separated by a space, e.g. 'gps xrd las'. All columns, which contain - any of these strings are uploaded. keys = None defaults to self.keys. keys = '' returns all columns - """ - self.load() - self.gc = gspread.authorize(self._credentials) - self.order_df() - if keys is None: - keys = self.keys - - self.ws = self.gc.open_by_key(self._spreadsheet_key).worksheet(worksheet) - if len(keys) > 0: - keys = keys + " type" - upload_df = self._query_by_keys(keys=keys, df=df) - else: - upload_df = df - if df is None: - upload_df = self.adj_df - upload_df = upload_df[ - upload_df["metadata"]["type"].str.contains("scan", na=False) - ] - gd.set_with_dataframe(self.ws, upload_df, include_index=True, col=2) - gf_dataframe.format_with_dataframe( - self.ws, upload_df, include_index=True, include_column_header=True, col=2 - ) - - def upload_pos(self, worksheet="positions", keys=None): - """ - This function uploads all entries with "type == pos" to the worksheet positions. - keys takes a list of strin All columns, which contain any of these strings are uploaded. - keys = None defaults to self.keys. keys = [] returns all columns - """ - self.load() - self.gc = gspread.authorize(self._credentials) - self.order_df() - if keys is None: - keys = self.keys - - self.ws = self.gc.open_by_key(self._spreadsheet_key).worksheet(worksheet) - if len(keys) > 0: - keys = keys + " metadata" - upload_df = self._query_by_keys(keys=keys) - else: - upload_df = self.adj_df - upload_df = upload_df[ - upload_df["metadata"]["type"].str.contains("pos", na=False) - ] - gd.set_with_dataframe(self.ws, upload_df, include_index=True, col=2) - gf_dataframe.format_with_dataframe( - self.ws, upload_df, include_index=True, include_column_header=True, col=2 - ) - - def _upload_all(self): - try: - self.upload_rt() - self.upload_pos() - except: - print( - f"Uploading of runtable to gsheet https://docs.google.com/spreadsheets/d/{self._spreadsheet_key}/ failed. Run run_table.upload_rt() for error traceback" - ) - - def upload_all(self): - rt = threading.Thread(target=self._upload_all) - rt.start() - - def _orderlist(self, mylist, key_order, orderlist=None): - key_order = key_order.split(" ") - if orderlist == None: - index = np.concatenate( - [np.where(np.array(mylist) == k)[0] for k in key_order if k in mylist] - ) - # index = np.array([mylist.index(k) for k in key_order if k in mylist]) - else: - index = np.concatenate( - [ - np.where(np.array(orderlist) == k)[0] - for k in key_order - if k in orderlist - ] - ) - curidx = np.arange(len(mylist)) - newidx = np.append(index, np.delete(curidx, index)) - return [mylist[n] for n in newidx] - - def order_df(self, key_order=None): - """ - This function orders the columns of the stored dataframe by the given key_order. - key_order is a string with consecutive keys such as 'name type pulse_id. It defaults to self.key_order' - """ - if key_order is None: - key_order = self.key_order - # self.alias_df = self.alias_df[ - # self._orderlist(list(self.alias_df.columns), key_order) - # ] - devs = [item[0] for item in list(self.adj_df.columns)] - self.adj_df = self.adj_df[ - self._orderlist(list(self.adj_df.columns), key_order, orderlist=devs) - ] - - def _get_adjustable_values(self, silent=True): - """ - This function gets the values of all adjustables in good adjustables and raises an error, when an adjustable is not connected anymore - """ - if silent: - dat = {} - for devname, dev in self.good_adjustables.items(): - dat[devname] = {} - for adjname, adj in dev.items(): - bad_adjs = [] - try: - dat[devname][adjname] = adj.get_current_value() - except: - print( - f"run_table: getting value of {devname}.{adjname} failed, removing it from list of good adjustables" - ) - bad_adjs.append(adjname) - for ba in bad_adjs: - if not devname in self.bad_adjustables.keys(): - self.bad_adjustables[devname] = {} - self.bad_adjustables[devname][adjname] = self.good_adjustables[ - devname - ].pop(adjname) - else: - dat = { - devname: { - adjname: adj.get_current_value() for adjname, adj in dev.items() - } - for devname, dev in self.good_adjustables.items() - } - return dat - - def subtract_df(self, devs, ind1, ind2): - """ - This function is used to subtract one dataframe from another to show changes between entries. - devs='thc tht' would show the devices thc and tht and ind1=0, ind2='p0' the difference between - run 0 and saved position 0. - """ - df1 = self.query(devs, [ind1]) - df1 = df1[[type(val) is not str for val in df1]] - df2 = self.query(devs, [ind2]) - df2 = df2[[type(val) is not str for val in df2]] - df2.columns = df1.columns - return df1.subtract(df2) - - def _get_all_adjustables(self, device, pp_name=None): - if pp_name is not None: - name = ".".join([pp_name, device.name]) - else: - name = device.name - self.adjustables[name] = {} - for key in device.__dict__.keys(): - if ~np.any([s in key for s in self._parse_exclude_keys]): - value = device.__dict__[key] - if np.all( - [ - ~np.any( - [ - s in str(type(value)) - for s in self._adj_exclude_class_types - ] - ), - hasattr(value, "get_current_value"), - ] - ): - self.adjustables[name][key] = value - - if hasattr(device, "get_current_value"): - self.adjustables[name][".".join([name, "self"])] = device - - def _get_all_adjustables_fewerparents( - self, device, adj_prefix=None, parent_name=None - ): - if adj_prefix is not None: - name = ".".join([adj_prefix, device.name]) - else: - name = device.name - for key in device.__dict__.keys(): - if ~np.any([s in key for s in self._parse_exclude_keys]): - value = device.__dict__[key] - if np.all( - [ - ~np.any( - [ - s in str(type(value)) - for s in self._adj_exclude_class_types - ] - ), - hasattr(value, "get_current_value"), - ] - ): - if parent_name == device.name: - self.adjustables[parent_name][key] = value - else: - self.adjustables[parent_name][".".join([name, key])] = value - - if parent_name == device.name: - if hasattr(device, "get_current_value"): - self.adjustables[parent_name]["self"] = device - - def _parse_child_instances_fewerparents( - self, parent_class, adj_prefix=None, parent_name=None - ): - if parent_name is None: - parent_name = parent_class.name - self._get_all_adjustables_fewerparents(parent_class, adj_prefix, parent_name) - if parent_name is not parent_class.name: - if adj_prefix is not None: - adj_prefix = ".".join([adj_prefix, parent_class.name]) - else: - adj_prefix = parent_class.name - - sub_classes = [] - for key in parent_class.__dict__.keys(): - if ~np.any([s in key for s in self._parse_exclude_keys]): - s_class = parent_class.__dict__[key] - if np.all( - [ - hasattr(s_class, "__dict__"), - hasattr(s_class, "name"), - s_class.__hash__ is not None, - "eco" in str(type(s_class)), - ~np.any( - [ - s in str(type(s_class)) - for s in self._parse_exclude_class_types - ] - ), - ~np.any( - [ - key in s for s in parent_name.split(".") - ] - ), - ] - ): - print(key) - sub_classes.append(s_class) - return set(sub_classes).union( - [ - s - for c in sub_classes - for s in self._parse_child_instances_fewerparents( - c, adj_prefix, parent_name - ) - ] - ) - - def _parse_parent_fewerparents(self, parent=None, verbose=False): - if parent == None: - parent = self.devices - for key in parent.__dict__.keys(): - try: - if ~np.any([s in key for s in self._parse_exclude_keys]): - s_class = parent.__dict__[key] - if np.all( - [ - hasattr(s_class, "__dict__"), - hasattr(s_class, "name"), - s_class.__hash__ is not None, - "eco" in str(type(s_class)), - ~np.any( - [ - s in str(type(s_class)) - for s in self._parse_exclude_class_types - ] - ), - ] - ): - self.adjustables[s_class.name] = {} - if verbose: - print(key) - self._parse_child_instances_fewerparents(s_class) - except Exception as e: - print(e) - print(key) - # print(f"failed to parse {key} in runtable") - for name, value in self._channels_ca.get_current_value().items(): - self.adjustables[f"env_{name}"] = { - key: PvRecord(pvsetname=ch) for key, ch in value.items() - } - if verbose: - print("Done parsing, checking adjustables") - self._check_adjustables() - - def _parse_child_instances(self, parent_class, pp_name=None): - # try: - self._get_all_adjustables(parent_class, pp_name) - # except: - # print(f'Getting adjustables from {parent_class.name} failed') - # pass - if pp_name is not None: - pp_name = ".".join([pp_name, parent_class.name]) - else: - pp_name = parent_class.name - - sub_classes = [] - for key in parent_class.__dict__.keys(): - if ~np.any([s in key for s in self._parse_exclude_keys]): - s_class = parent_class.__dict__[key] - if np.all( - [ - hasattr(s_class, "__dict__"), - hasattr(s_class, "name"), - s_class.__hash__ is not None, - "eco" in str(type(s_class)), - ~np.any( - [ - s in str(type(s_class)) - for s in self._parse_exclude_class_types - ] - ), - ] - ): - sub_classes.append(s_class) - return set(sub_classes).union( - [s for c in sub_classes for s in self._parse_child_instances(c, pp_name)] - ) - - def _parse_parent(self, parent=None): - if parent == None: - parent = self.devices - for key in parent.__dict__.keys(): - try: - if ~np.any([s in key for s in self._parse_exclude_keys]): - s_class = parent.__dict__[key] - if np.all( - [ - hasattr(s_class, "__dict__"), - hasattr(s_class, "name"), - s_class.__hash__ is not None, - "eco" in str(type(s_class)), - ~np.any( - [ - s in str(type(s_class)) - for s in self._parse_exclude_class_types - ] - ), - ] - ): - self._parse_child_instances(parent.__dict__[key]) - except Exception as e: - print(e) - print(key) - # print(f"failed to parse {key} in runtable") - for name, value in self._channels_ca.get_current_value().items(): - self.adjustables[f"env_{name}"] = { - key: PvRecord(pvsetname=ch) for key, ch in value.items() - } - self._check_adjustables() - - def _check_adjustables(self, check_for_current_none_values=False): - good_adj = {} - bad_adj = {} - for device, adjs in self.adjustables.items(): - good_dev_adj = {} - bad_dev_adj = {} - for name, adj in adjs.items(): - if check_for_current_none_values and (adj.get_current_value() is None): - bad_dev_adj[name] = adj - else: - good_dev_adj[name] = adj - if len(good_dev_adj) > 0: - good_adj[device] = good_dev_adj - if len(bad_dev_adj) > 0: - bad_adj[device] = bad_dev_adj - self.good_adjustables = good_adj - self.bad_adjustables = bad_adj - - def set_alias_namespace(self, alias_namespace): - aliases = [s.replace(".", "_") for s in alias_namespace.aliases] - self._alias_namespace = alias_namespace - self._pvs = dict( - zip( - aliases, - np.array( - [ - PV(ch, connection_timeout=0.05, auto_monitor=True) - for ch in alias_namespace.channels - ] - ), - ) - ) - - def get_alias_namespace(self): - return self._alias_namespace - - alias_namespace = property(get_alias_namespace, set_alias_namespace) - - def __repr__(self): - self.order_df() - return_df = self._query_by_keys(self.keys) - return return_df.T.__repr__() - - class Gsheet_API: def __init__( self, @@ -997,6 +318,9 @@ class Run_Table2: def to_dataframe(self): return DataFrame(self._data) + def benchmark_times(self, plot=True, repeats=1): + return self._data.benchmark_times(plot=plot, repeats=repeats) + def _reduce_df( self, keys=None, @@ -1421,7 +745,7 @@ class Run_Table_DataFrame(DataFrame): self._check_adjustables() - def _check_adjustables(self, check_for_current_none_values=False): + def _check_adjustables(self, check_for_current_none_values=True): good_adj = {} bad_adj = {} for device, adjs in self.adjustables.items(): @@ -1467,6 +791,30 @@ class Run_Table_DataFrame(DataFrame): devs = [item[0] for item in list(self.columns)] self.df = self[self._orderlist(list(self.columns), key_order, orderlist=devs)] + def benchmark_times(self, repeats=1, plot=True): + ts = [] + devs=[] + def get_dev_adjs(dev): + for k, adj in dev.items(): + val = adj.get_current_value() + for k, dev in self.good_adjustables.items(): + def func(dev=dev): + return get_dev_adjs(dev) + t = timeit.timeit(func, number=repeats) + ts.append(float(t)) + devs.append(k) + print(k, t) + idx = np.argsort(ts) + print('results stored in run_table._data.times') + self.times = [np.array(devs)[idx], np.array(ts)[idx]] + if plot: + import pylab as plt + plt.figure('Run_table times required to get values') + plt.barh(self.times[0], self.times[1]) + plt.xlabel('time (s)') + return self.times + + def name2obj(obj_parent, name, delimiter="."): if type(name) is str: diff --git a/eco/xoptics/kb_bernina.py b/eco/xoptics/kb_bernina.py index 9d25bc4..9f3062f 100644 --- a/eco/xoptics/kb_bernina.py +++ b/eco/xoptics/kb_bernina.py @@ -53,7 +53,7 @@ class KBMirrorBernina(Assembly): self.d_prof_dsd = d_prof_dsd def calc_positions(self, the_kbver, the_kbhor): - """angles in rad""" + """angles in rad, positive only (i.e. describe incidence angles to KBs)""" pos_calc = {} pos_calc["y_kbhor"] = np.tan(2 * the_kbver) * np.abs( self.d_kbver - self.d_kbhor @@ -166,6 +166,8 @@ class KBMirrorBernina(Assembly): ocoo = self.usd_table.get_coordinates() odiffx = self.diffractometer.xbase.get_current_value() odiffy = self.diffractometer.ybase.get_current_value() + + # TODO implement motions for the angles as well. ISSUE is that the rx motion somehow decreases the distance to the usd too much for the shurt bellows (as of Feb 27 2023). odiffrx = self.diffractometer.rxbase.get_current_value() odiffnu = self.diffractometer.nu.get_current_value() odiffmu = self.diffractometer.mu.get_current_value() diff --git a/eco/xoptics/kb_mirrors.py b/eco/xoptics/kb_mirrors.py index 8b0a31b..1c8d1db 100644 --- a/eco/xoptics/kb_mirrors.py +++ b/eco/xoptics/kb_mirrors.py @@ -3,6 +3,7 @@ from ..devices_general.motors import MotorRecord from ..elements.adjustable import AdjustableVirtual from ..epics.adjustable import AdjustablePv, AdjustablePvEnum import numpy as np +from epics import PV class KbVer(Assembly): @@ -85,6 +86,22 @@ class KbVer(Assembly): self._append( MotorRecord, pvname + ":TX2", name="_X2", is_setting=True, is_display=False ) + self._pv_sync_world = PV(pvname + ":SYNC_AXES") + self._pv_amp_reset = PV(pvname + ":RESET_AMP.PROC") + self._pv_parkall = PV(pvname + "::KILL_ALL.PROC") + self._pv_enable_all = PV(pvname + ":ENABLE_ALL.PROC") + self._pv_sync_all_axes = PV(pvname + ":SYNC.PROC") + self._pv_safety_on = PV(pvname + ":SAFETY_ON.PROC") + self._pv_safety_off = PV(pvname + ":SAFETY_OFF.PROC") + + def sync_world(self): + self._pv_sync_world.put(1) + + def sync_phys_axes(self): + self._pv_sync_all_axes.put(1) + + def park_all(self): + self._pv_parkall.put(1) def _get_bend_mean(self): return float( @@ -189,6 +206,22 @@ class KbHor(Assembly): self._append( MotorRecord, pvname + ":TX2", name="_X2", is_setting=True, is_display=False ) + self._pv_sync_world = PV(pvname + ":SYNC_AXES") + self._pv_amp_reset = PV(pvname + ":RESET_AMP.PROC") + self._pv_parkall = PV(pvname + "::KILL_ALL.PROC") + self._pv_enable_all = PV(pvname + ":ENABLE_ALL.PROC") + self._pv_sync_all_axes = PV(pvname + ":SYNC.PROC") + self._pv_safety_on = PV(pvname + ":SAFETY_ON.PROC") + self._pv_safety_off = PV(pvname + ":SAFETY_OFF.PROC") + + def sync_world(self): + self._pv_sync_world.put(1) + + def sync_phys_axes(self): + self._pv_sync_all_axes.put(1) + + def park_all(self): + self._pv_parkall.put(1) def _get_bend_mean(self): return float( From 22cd9d89bef13fd5c1fc27dbd88423b7c1f86b56 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Wed, 15 Mar 2023 13:33:43 +0100 Subject: [PATCH 32/52] fixes --- eco/acquisition/daq_client.py | 7 +- eco/aliases/aliases.py | 2 +- eco/bernina/bernina.py | 68 +++++++--- eco/elements/adjustable.py | 6 +- eco/elements/assembly.py | 51 ++++++++ eco/elements/protocols.py | 13 +- eco/endstations/bernina_diffractometers.py | 29 +++-- eco/loptics/bernina_laser.py | 23 ++-- eco/timing/timing_diag.py | 2 +- eco/utilities/recspace.py | 139 +++++++++++++-------- eco/utilities/runtable.py | 96 +++++++++----- 11 files changed, 315 insertions(+), 121 deletions(-) diff --git a/eco/acquisition/daq_client.py b/eco/acquisition/daq_client.py index 377cf02..3480e00 100644 --- a/eco/acquisition/daq_client.py +++ b/eco/acquisition/daq_client.py @@ -48,7 +48,11 @@ class Daq(Assembly): self.pgroup = pgroup if type(pulse_id_adj) is str: self.pulse_id = DetectorPvDataStream(pulse_id_adj, name="pulse_id") - self._pid_wo_automonitor = PV("SGE-CPCW-85-EVR0:RX-PULSEID", connection_timeout=0.05, auto_monitor=False) + self._pid_wo_automonitor = PV( + "SGE-CPCW-85-EVR0:RX-PULSEID", + connection_timeout=0.05, + auto_monitor=False, + ) else: self.pulse_id = pulse_id_adj self.running = [] @@ -60,6 +64,7 @@ class Daq(Assembly): self.rate_multiplicator = rate_multiplicator def acquire(self, file_name=None, Npulses=100, acq_pars={}): + # print(acq_pars) print(file_name, Npulses) acquisition = Acquisition( acquire=None, diff --git a/eco/aliases/aliases.py b/eco/aliases/aliases.py index baf0de6..e755326 100644 --- a/eco/aliases/aliases.py +++ b/eco/aliases/aliases.py @@ -30,7 +30,7 @@ class Alias: def pop_object(self, obj): i = self.children.index(obj) - o = self.children[i] + o = self.children.pop(i) o.parent = None def get_all(self, joiner=".", channeltypes=None): diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 3eae5b2..b6fe7d3 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -419,19 +419,19 @@ namespace.append_obj( name="prof_dsd", lazy=True, ) -namespace.append_obj( - "SolidTargetDetectorPBPS", - "SARES20-DSDPBPS", - # diode_channels_raw={ - # "up": "", - # "down": "", - # "left": "", - # "right":"", - # }, - module_name="eco.xdiagnostics.intensity_monitors", - name="mon_dsd", - lazy=True, -) +# namespace.append_obj( +# "SolidTargetDetectorPBPS", +# "SARES20-DSDPBPS", +# # diode_channels_raw={ +# # "up": "", +# # "down": "", +# # "left": "", +# # "right":"", +# # }, +# module_name="eco.xdiagnostics.intensity_monitors", +# name="mon_dsd", +# lazy=True, +# ) ## general components ## namespace.append_obj( @@ -690,6 +690,12 @@ namespace.append_obj( name="xrd", lazy=True, ) +namespace.append_obj( + "Crystals", + module_name="eco.utilities.recspace", + name="diffcalc", + lazy=True, +) namespace.append_obj( "KBMirrorBernina", "SAROP21-OKBV139", @@ -1235,8 +1241,16 @@ def _create_metadata_structure_start_scan( if not append_status_info: return t_start_rt = time.time() + d = {} + ## use values from status for run_table try: - run_table.append_run(runno, metadata=metadata) + status = scan.status["status_run_start"] + d = status["settings"] + d.update(status["status"]) + except: + print("Tranferring values from status to run_table did not work") + try: + run_table.append_run(runno, metadata=metadata, d=d) except: print("WARNING: issue adding data to run table") print(f"RT appending: {time.time()-t_start_rt:.3f} s") @@ -1399,7 +1413,7 @@ namespace.append_obj( # namespace.append_obj( # "IncouplingCleanBernina", -# lazy=False, +# lazy=True, # name="las_inc", # module_name="eco.loptics.bernina_laser", # ) @@ -1512,14 +1526,13 @@ class N2jet(Assembly): ) -# ad hoc incoupling device +# # ad hoc incoupling device class Incoupling(Assembly): def __init__(self, name=None): super().__init__(name=name) - self._append(SmaractRecord, "SARES23:ESB11", name="pitch", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB10", name="pitch", is_setting=True) self._append(SmaractRecord, "SARES23:ESB13", name="roll", is_setting=True) # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) - # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) # self._append(SmaractRecord, "SARES23:ESB17", name="rotation", is_setting=True) @@ -1534,7 +1547,8 @@ namespace.append_obj( name="thc", lazy=True, module_name="eco.endstations.bernina_sample_environments", - configuration=["ottifant"], + # configuration=["ottifant"], + configuration=[], ) @@ -2160,3 +2174,19 @@ def name2pgroups(name): names = [i.name for i in dirs] targets = [i.resolve().name for i in dirs] return [[i_n, i_p] for i_n, i_p in zip(names, targets) if name in i_n] + + +namespace.append_obj( + "Jungfrau", + "JF03T01V02", + name="det_i0", + pgroup_adj=config_bernina.pgroup, + module_name="eco.detector", +) +namespace.append_obj( + "Jungfrau", + "JF01T03V01", + name="data", + pgroup_adj=config_bernina.pgroup, + module_name="eco.detector", +) diff --git a/eco/elements/adjustable.py b/eco/elements/adjustable.py index 08e6b57..2d4027e 100644 --- a/eco/elements/adjustable.py +++ b/eco/elements/adjustable.py @@ -309,7 +309,7 @@ class DummyAdjustable: self.alias = Alias(name) self.current_value = 0 - + self.limits = [-100,100] def get_current_value(self): return self.current_value @@ -320,6 +320,10 @@ class DummyAdjustable: return Changer( target=value, parent=self, changer=changer, hold=hold, stopper=None ) + def get_limits(self): + return self.limits + def set_limits(self, limits): + self.limits = limits def __repr__(self): name = self.name diff --git a/eco/elements/assembly.py b/eco/elements/assembly.py index 9987570..0902ae0 100644 --- a/eco/elements/assembly.py +++ b/eco/elements/assembly.py @@ -145,6 +145,57 @@ class Assembly: geterror.append(ts.alias.get_full_name(base=base)) else: nodet.append(ts.alias.get_full_name(base=base)) + + # with ThreadPoolExecutor(max_workers=max_workers) as exc: + # list( + # progress.track( + # exc.map( + # lambda name: self.init_name( + # name, verbose=verbose, raise_errors=raise_errors + # ), + # self.all_names + # - self.initialized_names + # - set(exclude_names), + # ), + # description="Initializing ...", + # total=len( + # self.all_names - self.initialized_names - set(exclude_names) + # ), + # transient=True, + # ) + # ) + + def get_stat_one_assembly(ts): + if hasattr(ts, "get_current_value"): + try: + if (not channeltypes) or (ts.alias.channeltype in channeltypes): + status[ + ts.alias.get_full_name(base=base) + ] = ts.get_current_value() + try: + status_channels[ + ts.alias.get_full_name(base=base) + ] = ts.alias.channel + except: + pass + except: + geterror.append(ts.alias.get_full_name(base=base)) + else: + nodet.append(ts.alias.get_full_name(base=base)) + + # with ThreadPoolExecutor(max_workers=max_workers) as exc: + # list( + # progress.track( + # exc.map( + # get_stat_one_assembly, + # self.status_collection.get_list(), + # ), + # description="Getting status...", + # total=len(self.status_collection.get_list()), + # transient=True, + # ) + # ) + for ts in track( self.status_collection.get_list(), transient=True, diff --git a/eco/elements/protocols.py b/eco/elements/protocols.py index 1da8bf0..9f4dc73 100644 --- a/eco/elements/protocols.py +++ b/eco/elements/protocols.py @@ -9,7 +9,6 @@ class Adjustable(Protocol): def set_target_value(self, value): ... - # def set_target_value(self,value) -> Changer:... @@ -17,3 +16,15 @@ class Adjustable(Protocol): class Detector(Protocol): def get_current_value(self): ... + + +@runtime_checkable +class ValueUpdateMonitorable(Protocol): + def get_current_value_callback(self): + ... + + +@runtime_checkable +class InitialisationWaitable(Protocol): + def _wait_for_initialisation(self): + ... diff --git a/eco/endstations/bernina_diffractometers.py b/eco/endstations/bernina_diffractometers.py index cae5402..bdc7ba2 100644 --- a/eco/endstations/bernina_diffractometers.py +++ b/eco/endstations/bernina_diffractometers.py @@ -14,7 +14,7 @@ from ..elements.assembly import Assembly from ..detector.jungfrau import Jungfrau from .kappa_conversion import kappa2you, you2kappa import numpy as np -from ..utilities.recspace import Crystals +from ..utilities.recspace import Crystals, DiffGeometryYou def addMotorRecordToSelf(self, name=None, Id=None): @@ -33,6 +33,7 @@ class GPS(Assembly): configuration=["base"], alias_namespace=None, fina_hex_angle_offset=None, + diffcalc=False, ): super().__init__(name=name) self.pvname = pvname @@ -275,7 +276,15 @@ class GPS(Assembly): unit="deg", ) - # self._append(Crystals, diffractometer_you=self, name="crystals", is_display="recursive") + if diffcalc: + self._append( + Crystals, + diffractometer_you=self, + name="diffcalc", + is_setting=False, + is_display=False, + ) + def gui(self, guiType="xdm"): """Adjustable convention""" @@ -406,6 +415,7 @@ class XRDYou(Assembly): diff_detector=None, invert_kappa_ellbow=True, pgroup_adj=None, + diffcalc=True, ): """X-ray diffractometer platform in AiwssFEL Bernina.\ : list of elements mounted on @@ -771,13 +781,14 @@ class XRDYou(Assembly): pgroup_adj=pgroup_adj, view_toplevel_only=True, ) - self._append( - Crystals, - diffractometer_you=self, - name="crystals", - is_setting=False, - is_display=False, - ) + if diffcalc: + self._append( + Crystals, + diffractometer_you=self, + name="diffcalc", + is_setting=False, + is_display=False, + ) def get_adjustable_positions_str(self): ostr = "*****XRD motor positions******\n" diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index a5091bb..f1b87cb 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -21,9 +21,9 @@ ureg = UnitRegistry() class IncouplingCleanBernina(Assembly): def __init__(self, name=None): super().__init__(name=name) - self._append(SmaractStreamdevice, "SARES23-ESB13", name="tilt") - self._append(SmaractStreamdevice, "SARES23-ESB14", name="rotation") - self._append(SmaractStreamdevice, "SARES23-LIC15", name="transl_vertical") + self._append(SmaractRecord, "SARES23:LIC17", name="tilt") + self._append(SmaractRecord, "SARES23:LIC18", name="rotation") + self._append(SmaractRecord, "SARES23:LIC16", name="transl_vertical") self._append(MotorRecord, "SARES20-MF2:MOT_5", name="transl_horizontal") @@ -263,8 +263,7 @@ class LaserBernina(Assembly): # name="delaystage_thz", # is_setting=True, # ) - self._append(SmaractRecord, "SARES23:ESB3", name="pump_hor", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB18", name="pump_ver", is_setting=True) + class DelayTime(AdjustableVirtual): @@ -355,26 +354,32 @@ class PositionMonitors(Assembly): super().__init__(name=name) self._append( CameraPositionMonitor, - "SLAAR21-LCAM-C541", + "SLAAR21-LCAM-CS844", name="table1_angle", is_display="recursive", is_status=True, ) self._append( CameraPositionMonitor, - "SLAAR21-LCAM-C551", + "SLAAR21-LCAM-CS843", + name="table1_position", + is_display="recursive", + is_status=True, + ) + self._append( + CameraPositionMonitor, + "SLAAR21-LCAM-CS842", name="table2_angle", is_display="recursive", is_status=True, ) self._append( CameraPositionMonitor, - "SLAAR21-LCAM-C552", + "SLAAR21-LCAM-CS841", name="table2_position", is_display="recursive", is_status=True, ) - # self._append( # CameraPositionMonitor, # "SLAAR21-LCAM-C511", diff --git a/eco/timing/timing_diag.py b/eco/timing/timing_diag.py index c055867..a0b8669 100644 --- a/eco/timing/timing_diag.py +++ b/eco/timing/timing_diag.py @@ -81,7 +81,7 @@ class TimetoolBerninaUSD(Assembly): CameraBasler, pvname=microscope_pvname, name="camera_microscope", - camserver_alias=f"{name} ({microscope_pvname})", + camserver_alias="PROF_KB (SARES20-PROF141-M1)", is_setting=True, is_display=False, ) diff --git a/eco/utilities/recspace.py b/eco/utilities/recspace.py index ba981fb..1b34f8a 100644 --- a/eco/utilities/recspace.py +++ b/eco/utilities/recspace.py @@ -10,11 +10,20 @@ from PIL import Image # from diffcalc.ub import calc calc import UBCalculation, Crystal from eco.elements.assembly import Assembly -from eco.elements.adjustable import AdjustableMemory, AdjustableFS, AdjustableVirtual +from eco.elements.adjustable import AdjustableMemory, AdjustableFS, AdjustableVirtual, DummyAdjustable from typing import Tuple, Optional from eco.elements.adj_obj import AdjustableObject from epics import PV +class Diffractometer_Dummy(Assembly): + def __init__(self, *args, name=None, **kwargs): + Assembly.__init__(self, name=name) + self.configuration = ["base", "arm"] + adjs = ["nu", "mu", "delta", "eta", "chi", "phi"] + for adj in adjs: + self._append(DummyAdjustable, name=adj, is_setting=True, is_display=True) + +diffractometer_dummy = Diffractometer_Dummy(name = "dummy") class CrystalNew(Assembly): def __init__(self, *args, name=None, **kwargs): @@ -40,7 +49,7 @@ class CrystalNew(Assembly): class Crystals(Assembly): - def __init__(self, diffractometer_you=None, name=None): + def __init__(self, diffractometer_you=diffractometer_dummy, name=None): super().__init__(name=name) self.diffractometer = diffractometer_you self._append( @@ -50,22 +59,22 @@ class Crystals(Assembly): default_value={}, is_setting=True, ) - for key, [date, active] in self.crystal_list().items(): - if active: + for key, meta in self.crystal_list().items(): + if self.diffractometer.name in meta: self._append( DiffGeometryYou, diffractometer_you=self.diffractometer, name=key ) - def append_crystal(self, name=None): + def create_crystal(self, name=None): if name == None: name = input( "Please choose a name for your crystal (no spaces or other special characters):" ) - specials = np.array([" ", "/", "(", ")", "[", "]"]) + specials = np.array([" ", "/", "(", ")", "[", "]"]+list(self.crystal_list.keys())) in_name = np.array([s in name for s in specials]) if np.any(in_name): raise Exception( - f"Special character(s) {specials[in_name]} in name not allowed" + f"Special character(s) {specials[in_name]} in name not allowed or name already exists" ) self._append( DiffGeometryYou, @@ -75,21 +84,38 @@ class Crystals(Assembly): is_display=False, ) crystals = self.crystal_list() - crystals[name] = [str(datetime.now()), 1] + crystals[name] = [str(datetime.now()), self.diffractometer.name] self.crystal_list.mv(crystals) self.__dict__[name].new_ub() - def remove_crystal(self, name=None): + def delete_crystal(self, name=None): """ - Remove crystal with a given name, deletes also the files. + Delete crystal with a given name, deletes also the files. """ + if name==None: + crystal_names = list(self.crystal_list().keys()) + input_message = "Select the crystal to delete:\nq) quit\n" + for index, crystal in enumerate(crystal_names): + input_message += f'{index:2}) {crystal:15}\n' + input_message += 'Your choice: ' + idx = '' + while idx not in range(len(crystal_names)): + if idx == 'q': + break + idx = int(input(input_message)) + print(f'Selected crystal: {crystal_names[idx]}') + name = crystal_names[idx] sure = "n" sure = input( f"are you sure you want to permanently remove the crystal {name} and its UB matrix and memories (y/n)? " ) if sure == "y": crystals = self.crystal_list() + meta = crystals[name] + if self.diffractometer.name in meta: + self.deactivate_crystal(name=name) removed = crystals.pop(name) + del removed self.crystal_list.mv(crystals) attrs = [ "unit_cell", @@ -107,41 +133,58 @@ class Crystals(Assembly): f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_{a}" ) - def activate_crystal(self): + def activate_crystal(self, name=None): crystals = self.crystal_list() - inactive_crystals = [k for k in crystals.keys() if crystals[k][1]==0] - idx = '' - input_message = "Select the crystal to activate:\n" - for index, crystal in enumerate(inactive_crystals): - input_message += f'{index:2}) {crystal:15}\n' - input_message += 'Your choice: ' - while idx not in range(len(inactive_crystals)): - idx = int(input(input_message)) - print(f'Selected crystal: {inactive_crystals[idx]}') - name = inactive_crystals[idx] + if name==None: + inactive_crystals = [k for k in crystals.keys() if not self.diffractometer.name in crystals[k]] + idx = '' + input_message = "Select the crystal to activate:\nq) quit\n" + for index, crystal in enumerate(inactive_crystals): + input_message += f'{index:2}) {crystal:15}\n' + input_message += 'Your choice: ' + while idx not in range(len(inactive_crystals)): + if idx == 'q': + break + idx = int(input(input_message)) + print(f'Activated crystal: {inactive_crystals[idx]}') + name = inactive_crystals[idx] self._append( - DiffGeometryYou, diffractometer_you=self.diffractometer, name=name + DiffGeometryYou, + diffractometer_you=self.diffractometer, + name=name, + is_setting=True, + is_display=False, ) - - - - def deactivate_crystal(self): - crystals = self.crystal_list() - active_crystals = [k for k in crystals.keys() if crystals[k][1]==1] - idx = '' - input_message = "Select the crystal to activate:\n" - for index, crystal in enumerate(active_crystals): - input_message += f'{index:2}) {crystal:15}\n' - input_message += 'Your choice: ' - while idx not in range(len(active_crystals)): - idx = int(input(input_message)) - print(f'Selected crystal: {active_crystals[idx]}') - name = active_crystals[idx] meta = crystals[name] - meta[1] = 0 + if not self.diffractometer.name in meta: + meta = meta + [self.diffractometer.name] + crystals[name] = meta + self.crystal_list.mv(crystals) + + def deactivate_crystal(self, name=None): + crystals = self.crystal_list() + if name==None: + active_crystals = [k for k in crystals.keys() if self.diffractometer.name in crystals[k]] + idx = '' + input_message = "Select the crystal to activate:\nq) quit\n" + for index, crystal in enumerate(active_crystals): + input_message += f'{index:2}) {crystal:15}\n' + input_message += 'Your choice: ' + while idx not in range(len(active_crystals)): + if idx == "q": + break + idx = int(input(input_message)) + print(f'Selected crystal: {active_crystals[idx]}') + name = active_crystals[idx] + meta = crystals[name] + if self.diffractometer.name in meta: + i = meta.index(self.diffractometer.name) + meta.pop(i) crystals[name] = meta self.crystal_list.mv(crystals) removed = self.__dict__.pop(name) + self.alias.pop_object(removed.alias) + del removed class DiffGeometryYou(Assembly): def __init__(self, diffractometer_you=None, name=None): @@ -228,22 +271,16 @@ class DiffGeometryYou(Assembly): is_display="recursive", ) - cfg = self.diffractometer.configuration + adjs = ["nu", "mu", "delta", "eta", "chi", "phi"] - adjs = [] - if "base" in cfg: - adjs += ["mu"] - if "arm" in cfg: - adjs += ["nu", "delta"] + cfg = [] + if hasattr(self.diffractometer, "configuration"): + cfg = self.diffractometer.configuration if "kappa" in cfg: - adjs += ["eta_kap", "kappa", "phi_kap"] - adj_keys = [ - adj if adj in self.diffractometer.__dict__.keys() else adj + "_manual" - for adj in adjs - ] + adjs = ["nu", "mu", "delta", "eta_kap", "kappa", "phi_kap"] self._diff_adjs = { - adj: self.diffractometer.__dict__[adj_key] - for adj, adj_key in zip(adjs, adj_keys) + adj: self.diffractometer.__dict__[adj] if adj in self.diffractometer.__dict__.keys() else DummyAdjustable(name = adj+"dummy") + for adj in adjs } def get_h(*args, **kwargs): diff --git a/eco/utilities/runtable.py b/eco/utilities/runtable.py index 98d6ce8..26ecac3 100644 --- a/eco/utilities/runtable.py +++ b/eco/utilities/runtable.py @@ -300,8 +300,9 @@ class Run_Table2: self, runno, metadata, + d={}, ): - self._data.append_run(runno, metadata) + self._data.append_run(runno, metadata, d=d) if self._google_sheet_api is not None: df = self._reduce_df() self._google_sheet_api.upload_all(df=df) @@ -317,9 +318,19 @@ class Run_Table2: def to_dataframe(self): return DataFrame(self._data) + ###### diagnostic and convencience functions ###### - def benchmark_times(self, plot=True, repeats=1): - return self._data.benchmark_times(plot=plot, repeats=repeats) + def run_table_from_other_pgroup(pgroup): + """ + returns a run_table instance of the specified pgroup + note: this does neither replace the current run_table nor switch the automatic appending of data to a new run_table or pgroup + + usage: run_table_pxxx = run_table.run_table_from_other_pgroup('pxxx') + """ + return Run_Table2(data=f'/sf/bernina/data/{pgroup}/res/run_table/{pgroup}_runtable.pkl') + + def check_timeouts(self, include_bad_adjustables=True, plot=True, repeats=1): + return self._data.check_timeouts(include_bad_adjustables=include_bad_adjustables, plot=plot, repeats=repeats) def _reduce_df( self, @@ -375,6 +386,13 @@ class Run_Table2: def __repr__(self): return self.__str__() + ###### diagnostic and convencience functions ###### + def run_table_from_old_pgroup(pgroup): + return + + def check_timeouts(self, include_bad_adjustables=True, plot=True, repeats=1): + return self._data.check_timeouts(include_bad_adjustables=include_bad_adjustables, plot=plot, repeats=repeats) + class Run_Table_DataFrame(DataFrame): def __init__( @@ -464,11 +482,12 @@ class Run_Table_DataFrame(DataFrame): "to": 2, "steps": 51, }, + d={}, ): self.load() if len(self.adjustables) == 0: self._parse_parent_fewerparents() - dat = self._get_adjustable_values() + dat = self._get_adjustable_values(d=d) dat["metadata"] = metadata dat["metadata"]["time"] = datetime.now() names = ["device", "adjustable"] @@ -514,7 +533,7 @@ class Run_Table_DataFrame(DataFrame): # self.order_df() self.save() - def _get_adjustable_values(self, silent=True): + def _get_adjustable_values(self, silent=True, d={}): """ This function gets the values of all adjustables in good adjustables and raises an error, when an adjustable is not connected anymore """ @@ -524,6 +543,9 @@ class Run_Table_DataFrame(DataFrame): dat[devname] = {} bad_adjs = [] for adjname, adj in dev.items(): + if f'{devname}.{adjname}' in d.keys(): + dat[devname][adjname] = d[f'{devname}.{adjname}'] + continue try: dat[devname][adjname] = adj.get_current_value() except: @@ -540,7 +562,7 @@ class Run_Table_DataFrame(DataFrame): else: dat = { devname: { - adjname: adj.get_current_value() for adjname, adj in dev.items() + adjname: d[f'{devname}.{adjname}'] if f'{devname}.{adjname}' in d.keys() else adj.get_current_value() for adjname, adj in dev.items() } for devname, dev in self.good_adjustables.items() } @@ -791,28 +813,46 @@ class Run_Table_DataFrame(DataFrame): devs = [item[0] for item in list(self.columns)] self.df = self[self._orderlist(list(self.columns), key_order, orderlist=devs)] - def benchmark_times(self, repeats=1, plot=True): - ts = [] - devs=[] - def get_dev_adjs(dev): - for k, adj in dev.items(): - val = adj.get_current_value() - for k, dev in self.good_adjustables.items(): - def func(dev=dev): - return get_dev_adjs(dev) - t = timeit.timeit(func, number=repeats) - ts.append(float(t)) - devs.append(k) - print(k, t) - idx = np.argsort(ts) - print('results stored in run_table._data.times') - self.times = [np.array(devs)[idx], np.array(ts)[idx]] - if plot: - import pylab as plt - plt.figure('Run_table times required to get values') - plt.barh(self.times[0], self.times[1]) - plt.xlabel('time (s)') - return self.times + + #### diagnostic and convenience functions #### + def check_timeouts(self, include_bad_adjustables=True, repeats=1, plot=True): + if len(self.adjustables) == 0: + self._parse_parent_fewerparents() + ts = [] + devs=[] + def get_dev_adjs(dev): + for k, adj in dev.items(): + val = adj.get_current_value() + for k, dev in self.good_adjustables.items(): + def func(dev=dev): + return get_dev_adjs(dev) + t = timeit.timeit(func, number=repeats) + ts.append(float(t)) + devs.append(k) + print(k, t) + idx = np.argsort(ts) + self.times = [np.array(devs)[idx], np.array(ts)[idx]] + print('recorded adjustable results stored in run_table._data.times') + if include_bad_adjustables: + for k, dev in self.bad_adjustables.items(): + def func(dev=dev): + return get_dev_adjs(dev) + t = timeit.timeit(func, number=repeats) + ts.append(float(t)) + devs.append(k) + print(k, t) + idx = np.argsort(ts) + print('rejected timed out adjustable results stored in run_table._data.times_rejected') + self.times_rejected = [np.array(devs)[idx], np.array(ts)[idx]] + + if plot: + import pylab as plt + fig, ax = plt.subplots(1) + if include_bad_adjustables: + plt.barh(self.times_rejected[0], self.times_rejected[1], color='red', label='rejected adjustables') + plt.barh(self.times[0], self.times[1], label='recorded adjustables', color='seagreen') + plt.xlabel('time (s)') + plt.legend() From a7df23a8ae805ad54a9f32ab8077b62ace11716e Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Tue, 25 Apr 2023 21:28:03 +0200 Subject: [PATCH 33/52] fixes and new reflaser --- .vscode/settings.json | 6 ++- eco/acquisition/daq_client.py | 2 +- eco/acquisition/scan.py | 2 - eco/bernina/bernina.py | 33 ++++++++----- eco/bernina/bernina_beamline.py | 87 +++++++++++++++++++++++++++++++++ eco/xoptics/reflaser.py | 68 +++++++++++++++++++++++++- 6 files changed, 181 insertions(+), 17 deletions(-) create mode 100644 eco/bernina/bernina_beamline.py diff --git a/.vscode/settings.json b/.vscode/settings.json index fcb1936..5e5af6a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,9 @@ { "python.linting.pylintEnabled": true, "python.linting.enabled": true, - "python.pythonPath": "/sf/bernina/applications/bm/envs/bernina38/bin/python" + "python.pythonPath": "/sf/bernina/applications/bm/envs/bernina38/bin/python", + "[python]": { + "editor.defaultFormatter": "ms-python.black-formatter" + }, + "python.formatting.provider": "none" } \ No newline at end of file diff --git a/eco/acquisition/daq_client.py b/eco/acquisition/daq_client.py index 3480e00..37b459c 100644 --- a/eco/acquisition/daq_client.py +++ b/eco/acquisition/daq_client.py @@ -64,7 +64,7 @@ class Daq(Assembly): self.rate_multiplicator = rate_multiplicator def acquire(self, file_name=None, Npulses=100, acq_pars={}): - # print(acq_pars) + print(acq_pars) print(file_name, Npulses) acquisition = Acquisition( acquire=None, diff --git a/eco/acquisition/scan.py b/eco/acquisition/scan.py index 158193c..350f9e0 100755 --- a/eco/acquisition/scan.py +++ b/eco/acquisition/scan.py @@ -60,7 +60,6 @@ class Scan: callbacks_end_scan=[], checker_sleep_time=2, return_at_end="question", - run_table=None, run_number=None, elog=None, **kwargs_callbacks, @@ -68,7 +67,6 @@ class Scan: if np.any([char in fina for char in inval_chars]): raise ScanNameError self.Nsteps = len(values) - self._run_table = run_table if not isinstance(Npulses, Number): if not len(Npulses) == len(values): raise ValueError("steps for Number of pulses and values must match!") diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index b6fe7d3..923e453 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -287,9 +287,17 @@ namespace.append_obj( "RefLaser_Aramis", "SAROP21-OLAS134", module_name="eco.xoptics.reflaser", + name="reflaser_beamline", + lazy=True, +) + +namespace.append_obj( + "RefLaser_BerninaUSD", + module_name="eco.xoptics.reflaser", name="reflaser", lazy=True, ) + namespace.append_obj( "SpectralEncoder", "SAROP21-PSEN135", @@ -1042,6 +1050,7 @@ def _increment_daq_run_number(scan, daq=daq, **kwargs): try: daq_last_run_number = daq.get_last_run_number() if int(scan.run_number) is int(daq_last_run_number) + 1: + print('############ incremented ##########') daq_run_number = daq.get_next_run_number() else: daq_run_number = daq_last_run_number @@ -1785,15 +1794,15 @@ from ..microscopes import MicroscopeMotorRecord # ) -delaystage_glob = MotorRecord( - "SLAAR21-LMOT-M523:MOTOR_1", - name="delaystage_glob", -) +# delaystage_glob = MotorRecord( +# "SLAAR21-LMOT-M523:MOTOR_1", +# name="delaystage_glob", +# ) -delay_glob = DelayTime( - delaystage_glob, - name="delay_glob", -) +# delay_glob = DelayTime( +# delaystage_glob, +# name="delay_glob", +# ) namespace.append_obj( "SwissFel", @@ -1936,19 +1945,19 @@ namespace.append_obj( "SlitBladesGeneral", name="slit_cleanup_air", def_blade_up={ - "args": [MotorRecord, "SARES20-MF1:MOT_10"], + "args": [MotorRecord, "SARES20-MF1:MOT_5"], "kwargs": {"is_psi_mforce": True}, }, def_blade_down={ - "args": [MotorRecord, "SARES20-MF1:MOT_11"], + "args": [MotorRecord, "SARES20-MF1:MOT_4"], "kwargs": {"is_psi_mforce": True}, }, def_blade_left={ - "args": [MotorRecord, "SARES20-MF1:MOT_13"], + "args": [MotorRecord, "SARES20-MF1:MOT_3"], "kwargs": {"is_psi_mforce": True}, }, def_blade_right={ - "args": [MotorRecord, "SARES20-MF1:MOT_12"], + "args": [MotorRecord, "SARES20-MF1:MOT_2"], "kwargs": {"is_psi_mforce": True}, }, module_name="eco.xoptics.slits", diff --git a/eco/bernina/bernina_beamline.py b/eco/bernina/bernina_beamline.py new file mode 100644 index 0000000..39d15c6 --- /dev/null +++ b/eco/bernina/bernina_beamline.py @@ -0,0 +1,87 @@ + +# new beamline startup + +from eco import Assembly +from eco.xoptics.attenuator_aramis import AttenuatorAramis + + +namespace.append_obj( + "Att_usd", + name="att_usd", + module_name="eco.xoptics.att_usd", + xp=xp, + lazy=True, +) + +namespace.append_obj( + "SlitPosWidth", + "SAROP21-OAPU138", + name="slit_att", + lazy=True, + module_name="eco.xoptics.slits", +), + +namespace.append_obj( + "JJSlitUnd", + name="slit_und", + module_name="eco.xoptics.slits", + lazy=True, +) +namespace.append_obj( + "SlitBlades", + "SAROP21-OAPU092", + name="slit_switch", + module_name="eco.xoptics.slits", + lazy=True, +) +namespace.append_obj( + "SlitBlades", + "SAROP21-OAPU102", + name="slit_mono", + module_name="eco.xoptics.slits", + lazy=True, +) + + + { + "name": "pshut_und", + "type": "eco.xoptics.shutters:PhotonShutter", + "args": ["SARFE10-OPSH044:REQUEST"], + "kwargs": {}, + "z_und": 44, + "desc": "First shutter after Undulators", + }, + + { + "name": "xp", + "args": [], + "kwargs": { + "Id": "SAROP21-OPPI113", + "evronoff": "SGE-CPCW-72-EVR0:FrontUnivOut15-Ena-SP", + "evrsrc": "SGE-CPCW-72-EVR0:FrontUnivOut15-Src-SP", + }, + "z_und": 103, + "desc": "X-ray pulse picker", + "type": "eco.xoptics.pp:Pulsepick", + }, + + + { + "name": "att_fe", + "type": "eco.xoptics.attenuator_aramis:AttenuatorAramis", + "args": ["SARFE10-OATT053"], + "kwargs": {"shutter": Component("pshut_und")}, + "z_und": 53, + "desc": "Attenuator in Front End", + }, + + +class AttenuationFELBernina(Assembly): + def __init__(self, name=None): + super().__init__(name=name) + self._append( + AttenuatorAramis, "SAROP21-OATT135", set_limits=[], name="opt", shutter=None + ) + self._append( + AttenuatorAramis, "SARFE10-OATT053", set_limits=[], name="fe", shutter=None + ) diff --git a/eco/xoptics/reflaser.py b/eco/xoptics/reflaser.py index 7c1f8c5..28464b7 100644 --- a/eco/xoptics/reflaser.py +++ b/eco/xoptics/reflaser.py @@ -1,11 +1,77 @@ from enum import Enum from eco.elements.adjustable import AdjustableGetSet -from ..devices_general.motors import MotorRecord +from eco.epics.adjustable import AdjustablePvEnum +from ..devices_general.motors import MotorRecord, SmaractRecord from epics import PV from ..aliases import Alias, append_object_to_object from ..elements.assembly import Assembly +class RefLaser_BerninaUSD(Assembly): + def __init__( + self, + pvname_mirrortranslation="SARES23:LIC12", + pvname_onoff="SARES21-CPCL-PS7071:LV_OMPV_1_CH1_SWITCH_SP", + elog=None, + name=None, + ): + super().__init__(name=name) + self.elog = elog + # append_object_to_object(self, + + self._append( + SmaractRecord, pvname_mirrortranslation, name="x_mirror", is_setting=True + ) + self._append( + AdjustablePvEnum, pvname_onoff, name="laser_power", is_setting=True + ) + + def movein(self, wait=False): + + try: + self.presets.movein() + except: + print("No movein preset found.") + + def moveout(self, wait=False): + try: + self.presets.moveout() + except: + print("No moveout preset found.") + + # self._append( + # AdjustableGetSet, + # self.get_in_status, + # self.set, + # name="state", + # is_setting=False, + # ) + + # self._append(MotorRecord, self.Id + ":MOTOR_1", name="mirror", is_setting=True) + + # self._append( + # RefLaserLaser, + # self.Id, + # name="laser", + # is_setting=True, + # is_display="recursive", + # ) + # self._append( + # RefLaserAperture, + # "SAROP21-OLIR134", + # name="aperture", + # is_setting=True, + # is_display="recursive", + # ) + + # self._append(MotorRecord, pv_lir0 + ":MOTOR_MX", name="x_ap1", is_setting=True) + # self._append(MotorRecord, pv_lir0 + ":MOTOR_MY", name="y_ap1", is_setting=True) + # pv_lir1 = "SAROP21-OLIR138" # TODO hardcoded + # self._append(MotorRecord, pv_lir1 + ":MOTOR_MX", name="x_ap2", is_setting=True) + # self._append(MotorRecord, pv_lir1 + ":MOTOR_MY", name="y_ap2", is_setting=True) + # self.mirror.set_limits(-20, 0) + + class RefLaser_Aramis(Assembly): def __init__(self, Id, elog=None, name=None, inpos=-19, outpos=-5): super().__init__(name=name) From 07f6d9666e1d8f17b4790e9400cf8fd97bfbef91 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Wed, 26 Apr 2023 12:15:36 +0200 Subject: [PATCH 34/52] fixes addition dsd --- eco/bernina/bernina.py | 4 ++-- eco/xoptics/kb_bernina.py | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 923e453..5912312 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -1945,11 +1945,11 @@ namespace.append_obj( "SlitBladesGeneral", name="slit_cleanup_air", def_blade_up={ - "args": [MotorRecord, "SARES20-MF1:MOT_5"], + "args": [MotorRecord, "SARES20-MF1:MOT_4"], "kwargs": {"is_psi_mforce": True}, }, def_blade_down={ - "args": [MotorRecord, "SARES20-MF1:MOT_4"], + "args": [MotorRecord, "SARES20-MF1:MOT_5"], "kwargs": {"is_psi_mforce": True}, }, def_blade_left={ diff --git a/eco/xoptics/kb_bernina.py b/eco/xoptics/kb_bernina.py index 9f3062f..e6267c9 100644 --- a/eco/xoptics/kb_bernina.py +++ b/eco/xoptics/kb_bernina.py @@ -26,6 +26,7 @@ class KBMirrorBernina(Assembly): d_target=1520.0, d_att=1420.0, d_prof_dsd=3725.0, + d_plate_mondsd=3147.5, name=None, ): """All distances are from sample interaction point at straight beam (no kb deflection), the units are expected in mm""" @@ -51,6 +52,7 @@ class KBMirrorBernina(Assembly): self.d_win1 = d_win1 self.d_target = d_target self.d_prof_dsd = d_prof_dsd + self.d_plate_mondsd = d_plate_mondsd def calc_positions(self, the_kbver, the_kbhor): """angles in rad, positive only (i.e. describe incidence angles to KBs)""" @@ -65,12 +67,18 @@ class KBMirrorBernina(Assembly): pos_calc["ry_hex"] = 2 * the_kbhor pos_calc["x_diff"] = np.tan(2 * the_kbhor) * np.abs(self.d_kbhor) pos_calc["y_diff"] = np.tan(2 * the_kbver) * np.abs(self.d_kbver) - pos_calc["x_dsd"] = np.tan(2 * the_kbhor) * np.abs( + pos_calc["x_prof_dsd"] = np.tan(2 * the_kbhor) * np.abs( self.d_kbhor + self.d_prof_dsd ) - pos_calc["y_dsd"] = np.tan(2 * the_kbver) * np.abs( + pos_calc["y_prof_dsd"] = np.tan(2 * the_kbver) * np.abs( self.d_kbver + self.d_prof_dsd ) + pos_calc["x_plate_mon_dsd"] = np.tan(2 * the_kbhor) * np.abs( + self.d_kbhor + self.d_plate_mondsd + ) + pos_calc["y_plate_mon_dsd"] = np.tan(2 * the_kbver) * np.abs( + self.d_kbver + self.d_plate_mondsd + ) return pos_calc def calc_fwhm( From 452141093607c610779791f11d25fd421721b34b Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Thu, 27 Apr 2023 09:32:46 +0200 Subject: [PATCH 35/52] Fix/debug/add --- eco/bernina/bernina.py | 3 ++- eco/xdiagnostics/intensity_monitors.py | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 5912312..b0f6dd3 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -1539,8 +1539,9 @@ class N2jet(Assembly): class Incoupling(Assembly): def __init__(self, name=None): super().__init__(name=name) - self._append(SmaractRecord, "SARES23:ESB10", name="pitch", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB11", name="pitch", is_setting=True) self._append(SmaractRecord, "SARES23:ESB13", name="roll", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB10", name="transl", is_setting=True) # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) # self._append(SmaractRecord, "SARES23:ESB17", name="rotation", is_setting=True) diff --git a/eco/xdiagnostics/intensity_monitors.py b/eco/xdiagnostics/intensity_monitors.py index 1c651d6..cb3a61e 100755 --- a/eco/xdiagnostics/intensity_monitors.py +++ b/eco/xdiagnostics/intensity_monitors.py @@ -305,7 +305,7 @@ class SolidTargetDetectorPBPS(Assembly): is_display=False, ) - def get_calibration_values(self, seconds=5): + def get_calibration_values(self, seconds=5, return_data=False): self.x_diodes.set_target_value(0).wait() self.y_diodes.set_target_value(0).wait() ds = [ @@ -322,6 +322,8 @@ class SolidTargetDetectorPBPS(Assembly): print(f"Got {nsamples} samples in {seconds} s.") norm_diodes = [1 / tm / 4 for tm in mean] + if return_data: + return data,norm_diodes return norm_diodes def set_calibration_values(self, norm_diodes): @@ -989,7 +991,7 @@ class SolidTargetDetectorPBPS_assembly(Assembly): DetectorPvDataStream, calc["ypos"], name="ypos", is_setting=False ) - def get_calibration_values(self, seconds=5): + def get_calibration_values(self, seconds=5, return_data=False): self.x_diodes.set_target_value(0).wait() self.y_diodes.set_target_value(0).wait() ds = [self.signal_up, self.signal_down, self.signal_left, self.signal_right] @@ -998,6 +1000,8 @@ class SolidTargetDetectorPBPS_assembly(Assembly): mean = [np.mean(td) for td in data] std = [np.std(td) for td in data] norm_diodes = [1 / tm / 4 for tm in mean] + if return_data: + return data,norm_diodes return norm_diodes def set_calibration_values(self, norm_diodes): From eba351aeb754d174cfa2fb79fd88344728aae97f Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Tue, 2 May 2023 11:06:13 +0200 Subject: [PATCH 36/52] setup tyburski --- eco/bernina/bernina.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index b0f6dd3..81352ba 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -1539,9 +1539,9 @@ class N2jet(Assembly): class Incoupling(Assembly): def __init__(self, name=None): super().__init__(name=name) - self._append(SmaractRecord, "SARES23:ESB11", name="pitch", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB13", name="roll", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB10", name="transl", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB11", name="rz", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB13", name="ry", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB10", name="x", is_setting=True) # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) # self._append(SmaractRecord, "SARES23:ESB17", name="rotation", is_setting=True) @@ -1552,6 +1552,21 @@ namespace.append_obj( name="las_inc", ) +class LaserSteering(Assembly): + def __init__(self, name=None): + super().__init__(name=name) + self._append(SmaractRecord, "SARES23:ESB3", name="mirr1_pitch", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB4", name="mirr1_roll", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB14", name="mirr2_pitch", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB12", name="mirr2_roll", is_setting=True) + +namespace.append_obj( + LaserSteering, + lazy=True, + name="las_pointing", +) + + namespace.append_obj( "High_field_thz_chamber", name="thc", From 885fe6e142712e760d973243b335bb89aad71216 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Fri, 5 May 2023 12:38:06 +0200 Subject: [PATCH 37/52] MPOD added --- eco/bernina/bernina.py | 12 ++++- eco/devices_general/powersockets.py | 69 ++++++++++++++++++++++++++++- eco/epics/adjustable.py | 22 +++++++++ eco/loptics/bernina_laser.py | 11 +++-- 4 files changed, 108 insertions(+), 6 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 81352ba..b5f54e2 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -1416,7 +1416,7 @@ namespace.append_obj( namespace.append_obj( "PositionMonitors", lazy=True, - name="las_pointing", + name="las_pointing_monitors", module_name="eco.loptics.bernina_laser", ) @@ -1566,6 +1566,16 @@ namespace.append_obj( name="las_pointing", ) +class RobotDetectorArm(Assembly): + def __init__(self, name=None): + super().__init__(name=name) + self._append(Jungfrau,'JF07T32V02',pgroup_adj=config_bernina.pgroup,name='det_diff') + +namespace.append_obj( + RobotDetectorArm, + lazy=True, + name="robot", +) namespace.append_obj( "High_field_thz_chamber", diff --git a/eco/devices_general/powersockets.py b/eco/devices_general/powersockets.py index 53db31b..84ef886 100644 --- a/eco/devices_general/powersockets.py +++ b/eco/devices_general/powersockets.py @@ -1,6 +1,7 @@ -from ..epics.adjustable import AdjustablePvEnum, AdjustablePvString +from ..epics.adjustable import AdjustablePvEnum, AdjustablePvString, AdjustablePv from ..elements.assembly import Assembly from ..epics.detector import DetectorPvEnum, DetectorPvData +from eco.elements.adjustable import spec_convenience class PowerSocket(Assembly): @@ -65,3 +66,69 @@ class GudeStrip(Assembly): self._append( DetectorPvData, pvbase + ":VOLTAGE", is_display=True, name="voltage" ) + + + +class MpodStatus(Assembly): + def __init__(self,pvbase,channel_number, module_string='LV_OMPV_1', name=None): + super().__init__(name=name) + self.pvbase = pvbase + self._module_string = module_string + self.channel_number = channel_number + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_ON',name='is_on') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_INHIBIT',name='inhibited') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_FAILURE_MIN_SENS_VOLTAGE',name='voltage_readback_low') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_FAILURE_MAX_SENS_VOLTAGE',name='voltage_readback_high') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_FAILURE_MAX_TERM_VOLTAGE',name='terminal_voltage_readback_high') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_FAILURE_MAX_CURRENT',name='current_too_high') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_FAILURE_MAX_TEMP',name='temperature_high') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_FAILURE_MAX_POWER',name='output_power_high') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_TIMEOUT',name='communication_timeout') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_CURR_CTRL',name='constant_current_mode') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_RMP_UP',name='ramping_up') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_RMP_DOWN',name='ramping_down') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_KILL',name='kill_enabled') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_EMERGENCY_OFF',name='emergency_off') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_FINE_ADJUST',name='fine_adjustment') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_VOLTAGE_CTRL',name='constant_voltage_mode') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_LOW_CURR_MEAS',name='current_readback_range_low') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_OUT_CURR_OOB',name='current_readback_range_high') + self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_OVERCURRENT',name='overcurrent') + +@spec_convenience +class MpodChannel(Assembly): + def __init__(self,pvbase,channel_number, module_string='LV_OMPV_1', name=None): + super().__init__(name=name) + self.pvbase = pvbase + self._module_string = module_string + self.channel_number = channel_number + self._append(AdjustablePvEnum,self.pvbase+f':{self._module_string}_CH{self.channel_number}_SWITCH_SP', name='on', is_setting=True) + self._append(AdjustablePv, + self.pvbase+f':{self._module_string}_CH{self.channel_number}_OUTPUT_V_SP', + pvreadbackname = self.pvbase+f':{self._module_string}_CH{self.channel_number}_MEAS_SENS_V', + pvlowlimname = self.pvbase+f':{self._module_string}_CH{self.channel_number}_OUTPUT_V_SP.LOPR', + pvhighlimname = self.pvbase+f':{self._module_string}_CH{self.channel_number}_OUTPUT_V_SP.HOPR', + name='voltage', is_setting=True) + self._append(AdjustablePv, + self.pvbase+f':{self._module_string}_CH{self.channel_number}_RMP_UP_RATE_SP', + pvlowlimname = self.pvbase+f':{self._module_string}_CH{self.channel_number}_RMP_UP_RATE_SP.LOPR', + pvhighlimname = self.pvbase+f':{self._module_string}_CH{self.channel_number}_RMP_UP_RATE_SP.HOPR', + name='ramp_up', is_setting=True) + self._append(AdjustablePv, + self.pvbase+f':{self._module_string}_CH{self.channel_number}_RMP_DOWN_RATE_SP', + pvlowlimname = self.pvbase+f':{self._module_string}_CH{self.channel_number}_RMP_DOWN_RATE_SP.LOPR', + pvhighlimname = self.pvbase+f':{self._module_string}_CH{self.channel_number}_RMP_DOWN_RATE_SP.HOPR', + name='ramp_down', is_setting=True) + self._append(MpodStatus,self.pvbase, self.channel_number, self._module_string, name='flags') + + def get_current_value(self,*args,**kwargs): + return self.on.get_current_value(*args,**kwargs) + + def set_target_value(self,*args,**kwargs): + return self.on.set_target_value(*args,**kwargs) + +class MpodModule(Assembly): + def __init__(self,pvbase,N_channels=8, module_string='LV_OMPV_1', name=None): + super().__init__(name=name) + for n in range(1,N_channels+1): + self._append(MpodChannel,pvbase,channel_number=n, module_string=module_string,name=f'ch{n}') \ No newline at end of file diff --git a/eco/epics/adjustable.py b/eco/epics/adjustable.py index ecc7687..87f70d6 100644 --- a/eco/epics/adjustable.py +++ b/eco/epics/adjustable.py @@ -25,6 +25,8 @@ class AdjustablePv: self, pvsetname, pvreadbackname=None, + pvlowlimname=None, + pvhighlimname=None, accuracy=None, name=None, elog=None, @@ -56,6 +58,19 @@ class AdjustablePv: pvreadbackname, count=element_count, connection_timeout=0.05 ) self.pvname = pvreadbackname + + if pvlowlimname: + self._pvlowlim = PV( + pvlowlimname, count=element_count, connection_timeout=0.05 + ) + else: + self._pvlowlim = None + if pvhighlimname: + self._pvhighlim = PV( + pvhighlimname, count=element_count, connection_timeout=0.05 + ) + else: + self._pvhighlim = None self.alias = Alias(name, channel=pvreadbackname, channeltype="CA") def get_current_value(self, readback=True): @@ -81,6 +96,13 @@ class AdjustablePv: return change_done def change(self, value): + if self._pvlowlim: + if value < self._pvlowlim.get(): + raise Exception(f'Target value of {self.name} is smaller than limit value!') + if self._pvhighlim: + if self._pvhighlim.get() < value: + raise Exception(f'Target value of {self.name} is higher than limit value!') + self._pv.put(value) time.sleep(0.1) while self.get_change_done() == 0: diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index f1b87cb..a40c05a 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -182,13 +182,16 @@ class LaserBernina(Assembly): MotorRecord, self.pvname + "-M533:MOT", name="wp_pol", is_setting=True ) - self._append( - MotorRecord, self.pvname + "-M534:MOT", name="wp_att", is_setting=True - ) + #self._append( + # MotorRecord, self.pvname + "-M534:MOT", name="wp_att", is_setting=True + #) + #ad hoc for tyburskiy setup + self._append(SmaractRecord, "SARES23:LIC15", name="wp_att", is_setting=True) # ad hoc for 500nm setup # self._append(SmaractRecord, "SARES23:ESB3", name="wp_att", is_setting=True) + self._append( AdjustableFS, "/photonics/home/gac-bernina/eco/configuration/wp_att_calibration", @@ -233,7 +236,7 @@ class LaserBernina(Assembly): # self.pvname + "-M522:MOTOR_1", # name="delaystage_pump", # is_setting=True, - # ) + # )wp_att # self._append( # DelayTime, self.delaystage_pump, name="delay_pump", is_setting=True # ) From 07b6287cd04e7b0175815ee3f91f13cdbb7203b0 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Mon, 15 May 2023 17:14:16 +0200 Subject: [PATCH 38/52] fit dsds and usd --- eco/bernina/bernina.py | 100 +++++++++++++++++++++++++++-- eco/bernina/config.py | 31 +-------- eco/devices_general/env_sensors.py | 53 +++++++++++++++ eco/elements/assembly.py | 11 ++-- eco/endstations/hexapod.py | 14 +++- eco/xdiagnostics/dsd.py | 4 +- 6 files changed, 169 insertions(+), 44 deletions(-) create mode 100644 eco/devices_general/env_sensors.py diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index b5f54e2..62798fd 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -414,7 +414,7 @@ namespace.append_obj( namespace.append_obj( "DownstreamDiagnostic", - name="dsd", + name="dsd_table", module_name="eco.xdiagnostics.dsd", lazy=True, ) @@ -488,6 +488,14 @@ namespace.append_obj( name="tt_kb", lazy=True, ) +namespace.append_obj( + "HexapodSymmetrie", + name="usd_table", + module_name="eco.endstations.hexapod", + offset=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + lazy=True, +) + namespace.append_obj( "EventReceiver", "SARES20-CVME-01-EVR0", @@ -1050,7 +1058,7 @@ def _increment_daq_run_number(scan, daq=daq, **kwargs): try: daq_last_run_number = daq.get_last_run_number() if int(scan.run_number) is int(daq_last_run_number) + 1: - print('############ incremented ##########') + print("############ incremented ##########") daq_run_number = daq.get_next_run_number() else: daq_run_number = daq_last_run_number @@ -1552,24 +1560,32 @@ namespace.append_obj( name="las_inc", ) + class LaserSteering(Assembly): def __init__(self, name=None): super().__init__(name=name) self._append(SmaractRecord, "SARES23:ESB3", name="mirr1_pitch", is_setting=True) self._append(SmaractRecord, "SARES23:ESB4", name="mirr1_roll", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB14", name="mirr2_pitch", is_setting=True) + self._append( + SmaractRecord, "SARES23:ESB14", name="mirr2_pitch", is_setting=True + ) self._append(SmaractRecord, "SARES23:ESB12", name="mirr2_roll", is_setting=True) - + + namespace.append_obj( LaserSteering, lazy=True, name="las_pointing", ) + class RobotDetectorArm(Assembly): def __init__(self, name=None): super().__init__(name=name) - self._append(Jungfrau,'JF07T32V02',pgroup_adj=config_bernina.pgroup,name='det_diff') + self._append( + Jungfrau, "JF07T32V02", pgroup_adj=config_bernina.pgroup, name="det_diff" + ) + namespace.append_obj( RobotDetectorArm, @@ -1911,6 +1927,79 @@ namespace.append_obj( ############## experiment specific ############# +##combined delaystage with phase shifter motion## + + +class Stage_LXT_Delay(Assembly): + def __init__(self, name=None): + super().__init__(name=name) + self._append( + AdjustableFS, + "/photonics/home/gac-bernina/eco/configuration/p20794_phase_shifter_threshold", + name="thr", + default_value=-280e-12, + is_setting=True, + ) + self._append( + AdjustableFS, + "/photonics/home/gac-bernina/eco/configuration/p20794_phase_shifter_offset", + name="ps0", + default_value=-2.5006914999999344e-08, + is_setting=True, + ) + self._append( + AdjustableFS, + "/photonics/home/gac-bernina/eco/configuration/p20794_delay_stage_offset", + name="dp0", + default_value=0, + is_setting=True, + ) + + def get_comb_delay(pd, ps): + ps_rel = ps - self.ps0() + pd_rel = pd - self.dp0() + return ps_rel + pd_rel + + def set_comb_delay(delay): + if delay > self.thr(): + if np.abs(las.xlt() - self.ps0()) > 50e-15: + ps_pos = self.ps0() + else: + ps_pos = None + pd_pos = self.dp0() + delay + else: + ps_pos = self.ps0() + delay + pd_pos = self.dp0() + return pd_pos, ps_pos + + self._append( + AdjustableVirtual, + [las.delay_pump, las.xlt], + get_comb_delay, + set_comb_delay, + name="delay_combined", + ) + + +namespace.append_obj( + Stage_LXT_Delay, + name="stage_ps_delay", + lazy=True, +) + +# # self.combined_delay = AdjustableVirtual( +# # [self.delay_thz, self.delay_800_pump], +# # self.delay_get, +# # self.delay_set, +# # name="combined_delay", +# # ) + +# def thz_pol_set(self, val): +# return 1.0 * val, 1.0 / 2 * val + +# def thz_pol_get(self, val, val2): +# return 1.0 * val2 + namespace.append_obj( "Bernina_XEYE", @@ -1925,7 +2014,6 @@ namespace.append_obj( # try to append pgroup folder to path !!!!! This caused eco to run in a timeout without error traceback !!!!! try: - import sys from ..utilities import TimeoutPath diff --git a/eco/bernina/config.py b/eco/bernina/config.py index e59a687..101683b 100755 --- a/eco/bernina/config.py +++ b/eco/bernina/config.py @@ -233,28 +233,6 @@ components = [ # "args": ["SAROP21-PBPS133"], # "kwargs": {"VME_crate": "SAROP21-CVME-PBPS1", "link": 9}, # }, - { - "name": "mon_opt_old", - "z_und": 133, - "desc": "Intensity/position monitor after Optics hutch", - "type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS_new", - "args": ["SAROP21-PBPS133"], - "kwargs": { - "VME_crate": "SAROP21-CVME-PBPS1", - "link": 9, - "channels": { - "up": "SLAAR21-LSCP1-FNS:CH6:VAL_GET", - "down": "SLAAR21-LSCP1-FNS:CH7:VAL_GET", - "left": "SLAAR21-LSCP1-FNS:CH4:VAL_GET", - "right": "SLAAR21-LSCP1-FNS:CH5:VAL_GET", - }, - "calc": { - "itot": "SLAAR21-LTIM01-EVR0:CALCI", - "xpos": "SLAAR21-LTIM01-EVR0:CALCX", - "ypos": "SLAAR21-LTIM01-EVR0:CALCY", - }, - }, - }, { "name": "prof_opt", "args": ["SAROP21-PPRM133"] * 2, @@ -503,14 +481,7 @@ components = [ "default_file_path": f"/sf/bernina/data/{config['pgroup']}/res/%s", }, }, - { - "args": [], - "name": "usd_table", - "z_und": 141, - "desc": "Upstream diagnostics table", - "type": "eco.endstations.hexapod:HexapodSymmetrie", - "kwargs": {"offset": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]}, - }, + # { # "args": ["SARES23-"], # "name": "slit_kb", diff --git a/eco/devices_general/env_sensors.py b/eco/devices_general/env_sensors.py new file mode 100644 index 0000000..e6d3a4e --- /dev/null +++ b/eco/devices_general/env_sensors.py @@ -0,0 +1,53 @@ +from eco import Assembly +from eco.epics.adjustable import AdjustablePv, AdjustablePvEnum, AdjustablePvString +from eco.epics.detector import DetectorPvData +from epics import PV + + + + +class I2cChannel(Assembly): + def __init__(self, pvbase, channelnumber, name=None): + super().__init__(name=name) + self.pvbase = pvbase + self.channel_number = channelnumber + self._append( + AdjustablePvString, + f'{self.pvbase}_CH{self.channel_number}:PROCESS.DESC', + name="description", + is_setting=True, + ) + self._append(DetectorPvData,f'{self.pvbase}_CH{self.channel_number}:TEMP', has_unit=True, name='temperature') + self._append(DetectorPvData,f'{self.pvbase}_CH{self.channel_number}:HUMIREL', has_unit=True, name = 'humidity') + self._append(DetectorPvData,f'{self.pvbase}_CH{self.channel_number}:PRES', has_unit=True, name='pressure') + self._append(AdjustablePv,f'{self.pvbase}_CH{self.channel_number}:ONOFF', name='enabled', is_setting=True) + self._append(AdjustablePvEnum,f'{self.pvbase}_CH{self.channel_number}:SENSOR_TYPE', name='sensor_type', is_setting=True) + self._pv_init = PV(self.pvbase+':INIT.PROC') + + def get_current_value(self,*args,**kwargs): + return f'{self.temperature.get_current_value(*args,**kwargs):.2f}°C , {self.humidity.get_current_value(*args,**kwargs):.2f}%relHum, {self.pressure.get_current_value(*args,**kwargs):.2f} mB' + + # def set_target_value(self,*args,**kwargs): + # return self.enabled.set_target_value(*args,**kwargs) + + def initialize(self): + self._pv_init.put(1) + + + + +class I2cModule(Assembly): + def __init__(self,pvbase='SARES20-CI2C',N_channels=8, name=None): + super().__init__(name=name) + for n in range(4,N_channels+1): + self._append(I2cChannel,pvbase,channelnumber=n,name=f'ch{n}') + + +class BerninaEnvironment(Assembly): + def __init__(self,pvbases=['SLAAR21-LI2C01', 'SARES20-CI2C'],channels=[[1,2],[4,5,6,7,8]], name=None): + super().__init__(name=name) + for pvbase,channelnumbers in zip(pvbases,channels): + for n in channelnumbers: + self._append(I2cChannel,pvbase,channelnumber=n,name=f'ch{n}') + + diff --git a/eco/elements/assembly.py b/eco/elements/assembly.py index 0902ae0..e7ef06b 100644 --- a/eco/elements/assembly.py +++ b/eco/elements/assembly.py @@ -314,10 +314,13 @@ class Assembly: label = self.alias.get_full_name() + " status\n" return label + self.get_display_str() - def _run_cmd(self, line): - print(f"Starting following commandline silently:\n" + line) - with open(os.devnull, "w") as FNULL: - subprocess.Popen(line, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) + def _run_cmd(self, line, silent = True): + if silent: + print(f"Starting following commandline silently:\n" + line) + with open(os.devnull, "w") as FNULL: + subprocess.Popen(line, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) + else: + subprocess.Popen(line, shell=True) import epics.pv diff --git a/eco/endstations/hexapod.py b/eco/endstations/hexapod.py index 734053a..15dbf26 100644 --- a/eco/endstations/hexapod.py +++ b/eco/endstations/hexapod.py @@ -1,6 +1,7 @@ from epics import PV from ..elements.adjustable import AdjustableFS, AdjustableVirtual from ..epics.adjustable import AdjustablePv, AdjustablePvEnum +from ..epics.detector import DetectorPvData from time import sleep from ..aliases import append_object_to_object, Alias from scipy.spatial.transform import Rotation @@ -364,16 +365,17 @@ class HexapodPI_old: return self.__str__() -class HexapodSymmetrie: +class HexapodSymmetrie(Assembly): def __init__( self, pv_master="SARES20-HEXSYM", name="hex_usd", offset=[0, 0, 0, 0, 0, 0] ): - self.name = name + super().__init__(name=name) self.offset = offset self.pvname = pv_master self.coordinate_switch = AdjustablePvEnum( f"{self.pvname}:MOVE#PARAM:CM", name="hex_usd_coordinate_switch" ) + self.pvs_setpos = { "x": PV(f"{self.pvname}:MOVE#PARAM:X.VAL"), "y": PV(f"{self.pvname}:MOVE#PARAM:Y.VAL"), @@ -390,6 +392,14 @@ class HexapodSymmetrie: "ry": PV(f"{self.pvname}:POSMACH:RY"), "rz": PV(f"{self.pvname}:POSMACH:RZ"), } + + self._append(DetectorPvData, f"{self.pvname}:POSMACH:X", name="x") + self._append(DetectorPvData, f"{self.pvname}:POSMACH:Y", name="y") + self._append(DetectorPvData, f"{self.pvname}:POSMACH:Z", name="z") + self._append(DetectorPvData, f"{self.pvname}:POSMACH:RX", name="rx") + self._append(DetectorPvData, f"{self.pvname}:POSMACH:RY", name="ry") + self._append(DetectorPvData, f"{self.pvname}:POSMACH:RZ", name="rz") + self._ctrl_pv = PV(f"{self.pvname}:STATE#PANEL:SET.VAL") def set_coordinates(self, x, y, z, rx, ry, rz, relative_to_eco_offset=True): diff --git a/eco/xdiagnostics/dsd.py b/eco/xdiagnostics/dsd.py index 18ff37a..f384d92 100644 --- a/eco/xdiagnostics/dsd.py +++ b/eco/xdiagnostics/dsd.py @@ -31,8 +31,8 @@ class DownstreamDiagnostic(Assembly): x = np.tan(2 * theta_kbhor) / np.cos(2 * theta_kbver) * 6325 return x, y - def home(self): - self._run_cmd("python /ioc/qt/ESB_DSD_home.py SARES20-DSD") + def home(self,**kwargs): + self._run_cmd("python /ioc/qt/ESB_DSD_home.py SARES20-DSD", **kwargs) def gui(self): self._run_cmd("caqtdm -noMsg -macro P=SARES20-DSD /ioc/qt/ESB_DSD_motors.ui") From c37bd3b87d724a37772e2f0a5029a8f15ae10d53 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Mon, 5 Jun 2023 11:32:28 +0200 Subject: [PATCH 39/52] changes in env sensor wago alib and more. --- eco/bernina/bernina.py | 296 ++++++++++++++++++++--------- eco/devices_general/env_sensors.py | 2 +- eco/devices_general/wago.py | 28 +++ eco/elements/assembly.py | 13 +- eco/xoptics/att_usd.py | 155 +-------------- 5 files changed, 251 insertions(+), 243 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 62798fd..e708022 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -1334,22 +1334,30 @@ namespace.append_obj( module_name="eco.devices_general.cameras_ptz", ) +#namespace.append_obj( +# "BerninaInlineMicroscope", +# pvname_camera="SARES20-CAMS142-M3", +# lazy=True, +# name="samplecam_inline", +# module_name="eco.microscopes", +#) + namespace.append_obj( - "BerninaInlineMicroscope", - pvname_camera="SARES20-CAMS142-M3", + "CameraBasler", + "SARES20-CAMS142-C1", lazy=True, - name="samplecam_inline", + name="samplecam_front", module_name="eco.microscopes", ) -namespace.append_obj( - "MicroscopeMotorRecord", - pvname_camera="SARES20-CAMS142-C1", - lazy=True, - name="samplecam", - module_name="eco.microscopes", - pvname_zoom="SARES20-MF1:MOT_5", -) +#namespace.append_obj( +# "MicroscopeMotorRecord", +# pvname_camera="SARES20-CAMS142-C1", +# lazy=True, +# name="samplecam", +# module_name="eco.microscopes", +# pvname_zoom="SARES20-MF1:MOT_5", +#) # namespace.append_obj( # "MicroscopeMotorRecord", @@ -1368,22 +1376,23 @@ namespace.append_obj( # name="samplecam_sideview", # module_name="eco.devices_general.cameras_swissfel", # ) +namespace.append_obj( + "CameraBasler", + "SARES20-CAMS142-C2", + lazy=True, + name="samplecam_back_racks", + module_name="eco.devices_general.cameras_swissfel", +) namespace.append_obj( "CameraBasler", "SARES20-CAMS142-C3", lazy=True, - name="samplecam_sideview", + name="samplecam_back_door", module_name="eco.devices_general.cameras_swissfel", ) -namespace.append_obj( - "CameraBasler", - "SARES20-CAMS142-C2", - lazy=True, - name="samplecam_sideview_45deg_THC", - module_name="eco.devices_general.cameras_swissfel", -) + # namespace.append_obj( # "CameraBasler", @@ -1487,11 +1496,11 @@ class Double_Pulse_Pump(Assembly): ) -namespace.append_obj( - Double_Pulse_Pump, - lazy=True, - name="pump", -) +#namespace.append_obj( +# Double_Pulse_Pump, +# lazy=True, +# name="pump", +#) # ad hoc N2 jet readout @@ -1550,65 +1559,178 @@ class Incoupling(Assembly): self._append(SmaractRecord, "SARES23:ESB11", name="rz", is_setting=True) self._append(SmaractRecord, "SARES23:ESB13", name="ry", is_setting=True) self._append(SmaractRecord, "SARES23:ESB10", name="x", is_setting=True) - # self._append(SmaractRecord, "SARES23:ESB16", name="tilt", is_setting=True) - # self._append(SmaractRecord, "SARES23:ESB17", name="rotation", is_setting=True) - + self._append(MotorRecord, "SLAAR21-LMOT-M521:MOTOR_1", name="delaystage_eos", is_setting=True,) + self._append(DelayTime, self.delaystage_eos, name="delay_eos", is_setting=False, is_display=True) namespace.append_obj( Incoupling, lazy=True, - name="las_inc", + name="eos", ) +class Jungfraus(Assembly): + def __init__(self, name=None): + super().__init__(name=name) + self._append( + Jungfrau, "JF07T32V02", pgroup_adj=config_bernina.pgroup, name="diff" + ) + self._append( + Jungfrau, "JF03T01V02", name="i0", pgroup_adj=config_bernina.pgroup + ) + +namespace.append_obj( + Jungfraus, + lazy=True, + name="jfs", +) + +#namespace.append_obj( +# "High_field_thz_chamber", +# name="thc", +# lazy=True, +# module_name="eco.endstations.bernina_sample_environments", + # configuration=["ottifant"], +# configuration=[], +#) + +class Sample_stages(Assembly): + def __init__(self, name=None): + super().__init__(name=name) + self._append(MotorRecord, "SARES20-MF1:MOT_11", name="x", is_setting=True) + self._append(MotorRecord, "SARES20-MF1:MOT_9", name="y", is_setting=True) + +namespace.append_obj( + Sample_stages, + lazy=True, + name="sample", +) + class LaserSteering(Assembly): def __init__(self, name=None): super().__init__(name=name) self._append(SmaractRecord, "SARES23:ESB3", name="mirr1_pitch", is_setting=True) self._append(SmaractRecord, "SARES23:ESB4", name="mirr1_roll", is_setting=True) - self._append( - SmaractRecord, "SARES23:ESB14", name="mirr2_pitch", is_setting=True - ) + self._append(SmaractRecord, "SARES23:ESB14", name="mirr2_pitch", is_setting=True) self._append(SmaractRecord, "SARES23:ESB12", name="mirr2_roll", is_setting=True) - -namespace.append_obj( - LaserSteering, - lazy=True, - name="las_pointing", -) - - -class RobotDetectorArm(Assembly): +class THzGeneration(Assembly): def __init__(self, name=None): super().__init__(name=name) + self._append(SmaractRecord, "SARES23:LIC16", name="par_x", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB8", name="mirr_x", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB7", name="mirr_z", is_setting=True) + self._append(SmaractRecord, "SARES23:LIC18", name="mirr_ry", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB9", name="mirr_rz", is_setting=True) + self._append(SmaractRecord, "SARES23:LIC15", name="polarizer", is_setting=True) + +class THzVirtualStages(Assembly): + def __init__(self, name=None, mx=None, mz=None, px=None, pz=None): + super().__init__(name=name) + self._mx = mx + self._mz = mz + self._px = px + self._pz = pz self._append( - Jungfrau, "JF07T32V02", pgroup_adj=config_bernina.pgroup, name="det_diff" + AdjustableFS, + "/photonics/home/gac-bernina/eco/configuration/p21145_mirr_x0", + name="offset_mirr_x", + default_value=0, + is_setting=True, + ) + self._append( + AdjustableFS, + "/photonics/home/gac-bernina/eco/configuration/p21145_mirr_z0", + name="offset_mirr_z", + default_value=0, + is_setting=True, + ) + self._append( + AdjustableFS, + "/photonics/home/gac-bernina/eco/configuration/p21145_par_x0", + name="offset_par_x", + default_value=0, + is_setting=True, + ) + self._append( + AdjustableFS, + "/photonics/home/gac-bernina/eco/configuration/p21145_par_z0", + name="offset_par_z", + default_value=0, + is_setting=True, ) + def get_divergence(mx, px): + return px - self.offset_par_x() + def set_divergence(x): + mx = self.offset_mirr_x() + x + px = self.offset_par_x() + x + return mx,px + + def get_focus_z(mx, pz): + return pz - self.offset_par_z() + def set_focus_z(z): + mz = self.offset_mirr_z() + z + pz = self.offset_par_z() + z + return mz, pz + self._append( + AdjustableVirtual, + [mx, px], + get_divergence, + set_divergence, + name="divergence_virtual", + ) + self._append( + AdjustableVirtual, + [mz, pz], + get_focus_z, + set_focus_z, + name="focus_virtual", + ) + def set_offsets_to_current_value(self): + self.offset_mirr_x.mv(self._mx()) + self.offset_mirr_z.mv(self._mz()) + self.offset_par_x.mv(self._px()) + self.offset_par_z.mv(self._pz()) + + + + +class THz(Assembly): + def __init__(self, name=None): + super().__init__(name=name) + self._append(SmaractRecord, "SARES23:ESB6", name="par_x", is_setting=True) + self._append(MotorRecord, "SARES20-MF1:MOT_10", name="par_y", is_setting=True) + self._append(SmaractRecord, "SARES23:LIC13", name="par_z", is_setting=True) + self._append(SmaractRecord, "SARES23:LIC14", name="par_rx", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB15", name="par_ry", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB1", name="delaystage_thz", is_setting=True,) + self._append(DelayTime, self.delaystage_thz, name="delay_thz", is_setting=False, is_display=True,) + self._append(LaserSteering, name="ir_pointing", is_setting=False) + self._append(THzGeneration, name="generation", is_setting=False) + + ### Virtual stages ### + self._append( + THzVirtualStages, + name="virtual_stages", + mx=self.generation.mirr_x, + mz=self.generation.mirr_z, + px=self.generation.par_x, + pz = self.par_z, + is_setting=False) + + namespace.append_obj( - RobotDetectorArm, - lazy=True, - name="robot", + THz, + lazy=True, + name="thz", ) -namespace.append_obj( - "High_field_thz_chamber", - name="thc", - lazy=True, - module_name="eco.endstations.bernina_sample_environments", - # configuration=["ottifant"], - configuration=[], -) - - # class THz_in_air(Assembly): # def __init__(self, name=None): # super().__init__(name=name) -# self._append(SmaractRecord, "SARES23:ESB4", name="eos_rot", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB12", name="eos_tilt", is_setting=True) # self._append(SmaractRecord, "SARES23:ESB5", name="crystal_ROT", is_setting=True) # self._append(SmaractRecord, "SARES23:LIC15", name="ir_1_z", is_setting=True) # self._append(SmaractRecord, "SARES23:LIC13", name="ir_1_Ry", is_setting=True) @@ -1699,9 +1821,11 @@ namespace.append_obj( # namespace.append_obj( # THz_in_air, # lazy=True, -# name="tia", +# name="thz", # ) + + namespace.append_obj( "SmaractController", "SARES23:LIC", @@ -1981,11 +2105,11 @@ class Stage_LXT_Delay(Assembly): ) -namespace.append_obj( - Stage_LXT_Delay, - name="stage_ps_delay", - lazy=True, -) +#namespace.append_obj( +# Stage_LXT_Delay, +# name="stage_ps_delay", +# lazy=True, +#) # # self.combined_delay = AdjustableVirtual( # # [self.delay_thz, self.delay_800_pump], @@ -2001,16 +2125,16 @@ namespace.append_obj( # return 1.0 * val2 -namespace.append_obj( - "Bernina_XEYE", - zoomstage_pv=config_bernina.xeye.zoomstage_pv._value, - camera_pv=config_bernina.xeye.camera_pv._value, - bshost=config_bernina.xeye.bshost._value, - bsport=config_bernina.xeye.bsport._value, - name="xeye", - lazy=True, - module_name="eco.xdiagnostics.profile_monitors", -) +#namespace.append_obj( +# "Bernina_XEYE", +# zoomstage_pv=config_bernina.xeye.zoomstage_pv._value, +# camera_pv=config_bernina.xeye.camera_pv._value, +# bshost=config_bernina.xeye.bshost._value, +# bsport=config_bernina.xeye.bsport._value, +# name="xeye", +# lazy=True, +# module_name="eco.xdiagnostics.profile_monitors", +#) # try to append pgroup folder to path !!!!! This caused eco to run in a timeout without error traceback !!!!! try: @@ -2299,17 +2423,17 @@ def name2pgroups(name): return [[i_n, i_p] for i_n, i_p in zip(names, targets) if name in i_n] -namespace.append_obj( - "Jungfrau", - "JF03T01V02", - name="det_i0", - pgroup_adj=config_bernina.pgroup, - module_name="eco.detector", -) -namespace.append_obj( - "Jungfrau", - "JF01T03V01", - name="data", - pgroup_adj=config_bernina.pgroup, - module_name="eco.detector", -) +#namespace.append_obj( +# "Jungfrau", +# "JF03T01V02", +# name="det_i0", +# pgroup_adj=config_bernina.pgroup, +# module_name="eco.detector", +#) +#namespace.append_obj( +# "Jungfrau", +# "JF01T03V01", +# name="data", +# pgroup_adj=config_bernina.pgroup, +# module_name="eco.detector", +#) diff --git a/eco/devices_general/env_sensors.py b/eco/devices_general/env_sensors.py index e6d3a4e..87e67b4 100644 --- a/eco/devices_general/env_sensors.py +++ b/eco/devices_general/env_sensors.py @@ -44,7 +44,7 @@ class I2cModule(Assembly): class BerninaEnvironment(Assembly): - def __init__(self,pvbases=['SLAAR21-LI2C01', 'SARES20-CI2C'],channels=[[1,2],[4,5,6,7,8]], name=None): + def __init__(self,pvbases=['SLAAR21-LI2C01', 'SARES20-CI2C'],channels=[[1,2,3],[4,5,7,8]], name=None): super().__init__(name=name) for pvbase,channelnumbers in zip(pvbases,channels): for n in channelnumbers: diff --git a/eco/devices_general/wago.py b/eco/devices_general/wago.py index c4ad1c5..41745ca 100644 --- a/eco/devices_general/wago.py +++ b/eco/devices_general/wago.py @@ -36,6 +36,34 @@ class AnalogInput(Assembly): is_setting=False, is_display=False, ) + self._append( + AdjustablePv, + self.pvname + ".AOFF", + name="_adj_offset", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + self.pvname + ".ASLO", + name="_adj_slope", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + self.pvname + ".EOFF", + name="linear_calibration_offset", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePv, + self.pvname + ".ESLO", + name="linear_calibration_slope", + is_setting=True, + is_display=True, + ) def get_current_value(self): return self.value.get_current_value() diff --git a/eco/elements/assembly.py b/eco/elements/assembly.py index e7ef06b..61bc11c 100644 --- a/eco/elements/assembly.py +++ b/eco/elements/assembly.py @@ -2,7 +2,7 @@ from tkinter import W from numpy import isin -from eco.elements.protocols import Detector +from eco.elements.protocols import Detector, InitialisationWaitable from ..aliases import Alias from tabulate import tabulate import colorama @@ -314,11 +314,18 @@ class Assembly: label = self.alias.get_full_name() + " status\n" return label + self.get_display_str() - def _run_cmd(self, line, silent = True): + def _wait_for_initialisation(self, timeout=2): + for ton, to in self.__dict__.items(): + if isinstance(to, InitialisationWaitable): + to._wait_for_initialisation() + + def _run_cmd(self, line, silent=True): if silent: print(f"Starting following commandline silently:\n" + line) with open(os.devnull, "w") as FNULL: - subprocess.Popen(line, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) + subprocess.Popen( + line, shell=True, stdout=FNULL, stderr=subprocess.STDOUT + ) else: subprocess.Popen(line, shell=True) diff --git a/eco/xoptics/att_usd.py b/eco/xoptics/att_usd.py index 5cd8940..ec56b0c 100644 --- a/eco/xoptics/att_usd.py +++ b/eco/xoptics/att_usd.py @@ -12,157 +12,6 @@ import numpy as np from time import sleep -class att_usd_targets(Assembly): - def __init__(self, name=None, Id=None, alias_namespace=None, xp=None): - super().__init__(name=name) - self.Id = Id - # self.name = name - self.alias = Alias(name) - self.E = None - self.E_min = 1500 - self._sleeptime = 1 - self.motor_configuration = { - "transl": { - "id": "-LIC10", - "pv_descr": " ", - "type": 2, - "sensor": 1, - "speed": 250, - "home_direction": "back", - }, - } - self._xp = xp - self.E = None - - for name, config in self.motor_configuration.items(): - self._append( - SmaractStreamdevice, - pvname=Id + config["id"], - name=name, - is_setting=True, - is_display=False, - ) - - Al = materials.Al - self.targets = { - "mat": np.array([Al, Al, Al, Al, Al, Al, Al, Al]), - "d": np.array([0, 60, 160, 200, 300, 400, 500, 700]), - "pos": np.array([-35, -25, -15, -5, 5, 15, 25, 35]), - } - - def _updateE(self, energy=None, check_once=False): - while not energy: - energy = PV("SARUN03-UIND030:FELPHOTENE").value - energy = energy * 1000 - if energy < self.E_min: - energy = None - print( - f"Machine photon energy is below {self.E_min} - waiting for the machine to recover" - ) - sleep(self._sleeptime) - self.E = energy - print("Set energy to %s eV" % energy) - return - - def _calc_transmission(self): - t = np.array( - [ - np.exp(-d / mat.absorption_length(self.E)) - for d, mat in zip(self.targets["d"], self.targets["mat"]) - ] - ) - self.targets["t"] = t - - def _find_nearest(self, a, a0): - "Element in nd array `a` closest to the scalar value `a0`" - idx = np.abs(a - a0).argmin() - return idx, a[idx] - - def set_transmission(self, value): - self._updateE() - self._calc_transmission() - idx, t = self._find_nearest(self.targets["t"], value) - pos = self.targets["pos"][idx] - self._xp.close() - self.transl.mv(pos) - print(f"Set transmission to {t:0.2E} | Moving to target {idx} at pos {pos}") - while abs(pos - self.transl.get_current_value()) > 0.1: - sleep(0.1) - print("transmission changed") - self._xp.open() - - def get_current_value(self): - self._updateE() - self._calc_transmission() - idx, pos = self._find_nearest( - self.targets["pos"], self.transl.get_current_value() - ) - t = self.targets["t"][idx] - return t - - def set_stage_config(self): - for name, config in self.motor_configuration.items(): - mot = self.__dict__[name]._device - mot.put("NAME", config["pv_descr"]) - mot.put("STAGE_TYPE", config["type"]) - mot.put("SET_SENSOR_TYPE", config["sensor"]) - mot.put("CL_MAX_FREQ", config["speed"]) - sleep(0.5) - mot.put("CALIBRATE.PROC", 1) - - def home_smaract_stages(self, stages=None): - if stages == None: - stages = self.motor_configuration.keys() - print("#### Positions before homing ####") - print(self.__repr__()) - for name in stages: - config = self.motor_configuration[name] - mot = self.__dict__[name]._device - print( - "#### Homing {} in {} direction ####".format( - name, config["home_direction"] - ) - ) - sleep(1) - if config["home_direction"] == "back": - mot.put("FRM_BACK.PROC", 1) - while mot.get("STATUS") == 7: - sleep(1) - if mot.get("GET_HOMED") == 0: - print( - "Homing failed, try homing {} in forward direction".format(name) - ) - mot.put("FRM_FORW.PROC", 1) - elif config["home_direction"] == "forward": - mot.put("FRM_FORW.PROC", 1) - while mot.get("STATUS") == 7: - sleep(1) - if mot.get("GET_HOMED") == 0: - print( - "Homing failed, try homing {} in backward direction".format( - name - ) - ) - mot.put("FRM_BACK.PROC", 1) - - def get_adjustable_positions_str(self): - ostr = "*****att_usd target position******\n" - - for tkey, item in self.__dict__.items(): - if hasattr(item, "get_current_value"): - pos = item.get_current_value() - ostr += " " + tkey.ljust(17) + " : % 14g\n" % pos - pos = self.get_current_value() - ostr += " " + "Transmission".ljust(17) + " : % 14.02E\n" % pos - return ostr - - def __call__(self, *args, **kwargs): - self.set_transmission(*args, **kwargs) - - def __repr__(self): - return self.get_adjustable_positions_str() - - class Att_usd(Assembly): """This is an adjusted smaract record compatible version of the original att_usd by roman.""" @@ -172,8 +21,8 @@ class Att_usd(Assembly): self.E = None self.E_min = 1500 self._sleeptime = 1 - self._append(SmaractRecord, "SARES23:LIC10", name="transl_2", is_setting=True) - self._append(SmaractRecord, "SARES23:LIC3", name="transl_1", is_setting=True) + self._append(SmaractRecord, "SARES23:LIC10", name="transl_2", is_setting=True, is_display=True) + self._append(SmaractRecord, "SARES23:LIC3", name="transl_1", is_setting=True, is_display=True) self.motor_configuration = { "transl_2": { "id": "SARES23-LIC10", From 5f8361cc1ee3a69b735cc5d7eacfd8694a01e53b Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Mon, 5 Jun 2023 13:03:08 +0200 Subject: [PATCH 40/52] added calibration fucntionality on analog input (WIP4nice) --- eco/devices_general/wago.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/eco/devices_general/wago.py b/eco/devices_general/wago.py index 41745ca..7ea1388 100644 --- a/eco/devices_general/wago.py +++ b/eco/devices_general/wago.py @@ -10,6 +10,9 @@ from eco.epics.adjustable import ( class AnalogInput(Assembly): def __init__(self, pvname, name=None): + """Analog input, which is defined by a PV name. There are linear calibration + options (hidden adjustment and visible linear_calibration values): + value = raw*linear_calibration_slope + linear_calibration_offset""" super().__init__(name=name) self.pvname = pvname self._append( @@ -68,6 +71,27 @@ class AnalogInput(Assembly): def get_current_value(self): return self.value.get_current_value() + def reset_offset_current_value_to(self,value=0): + self.linear_calibration_offset.set_target_value( + (-1) + * self.raw.get_current_value() + * self.linear_calibration_slope.get_current_value() + * self._adj_slope.get_current_value() + + value + ).wait() + + def reset_slope_current_value_to(self,value=1): + oslo = self.linear_calibration_slope.get_current_value() + ooff = self.linear_calibration_offset.get_current_value() + self.linear_calibration_offset.set_target_value( + ooff/oslo + * self._adj_slope.get_current_value() + * value + ).wait() + ooff_raw = ooff / oslo / self._adj_slope.get_current_value() + nslo = value / (self.raw.get_current_value()-ooff_raw) + self.linear_calibration_slope.set_target_value(nslo).wait() + class WagoAnalogInputs(Assembly): def __init__(self, pvbase, name=None): From 1534cfff9a93adc80c7b7459018882de4dc1700e Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Thu, 22 Jun 2023 18:55:52 +0200 Subject: [PATCH 41/52] fixes --- eco/bernina/bernina.py | 324 +++++++++--------- eco/devices_general/wago.py | 18 +- eco/elements/assembly.py | 25 +- .../bernina_sample_environments.py | 68 ++-- eco/epics/adjustable.py | 25 +- eco/loptics/bernina_laser.py | 10 +- eco/timing/event_timing_new_new.py | 49 +-- eco/timing/lasertiming_edwin.py | 8 + eco/utilities/config.py | 7 +- 9 files changed, 304 insertions(+), 230 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index e708022..f724691 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -665,6 +665,16 @@ namespace.append_obj( name="analog_outputs", module_name="eco.devices_general.wago", ) + +namespace.append_obj( + "AnalogInput", + "SARES20-CWAG-GPS01:ADC08", + lazy=True, + name="oxygen_sensor", + module_name="eco.devices_general.wago", +) + + namespace.append_obj( "GudeStrip", "SARES20-CPPS-01", @@ -1369,13 +1379,13 @@ namespace.append_obj( # ) -# namespace.append_obj( -# "CameraBasler", -# "SARES20-CAMS142-M2", -# lazy=True, -# name="samplecam_sideview", -# module_name="eco.devices_general.cameras_swissfel", -# ) +namespace.append_obj( + "CameraBasler", + "SARES20-CAMS142-M2", + lazy=True, + name="samplecam_sideview", + module_name="eco.devices_general.cameras_swissfel", +) namespace.append_obj( "CameraBasler", "SARES20-CAMS142-C2", @@ -1450,50 +1460,50 @@ from ..devices_general.motors import SmaractStreamdevice from ..loptics.bernina_laser import DelayTime -# namespace.append_obj( -# "Organic_crystal_breadboard", -# lazy=True, -# name="ocb", -# module_name="eco.endstations.bernina_sample_environments", -# Id="SARES23", -# ) +namespace.append_obj( + "Organic_crystal_breadboard", + lazy=True, + name="ocb", + module_name="eco.endstations.bernina_sample_environments", + Id="SARES23", +) from ..epics.adjustable import AdjustablePv -class Double_Pulse_Pump(Assembly): - def __init__(self, name=None): - super().__init__(name=name) +# class Double_Pulse_Pump(Assembly): +# def __init__(self, name=None): +# super().__init__(name=name) - ### dp smaract stages #### +# ### dp smaract stages #### - self.motor_configuration = { - "delaystage_both": { - "id": "SARES23:ESB15", - }, - "delaystage_pulse2": { - "id": "SARES23:ESB1", - }, - "wp_both": { - "id": "SARES23:ESB3", - }, - "wp_pulse2": { - "id": "SARES23:ESB2", - }, - } - for name, config in self.motor_configuration.items(): - self._append( - SmaractRecord, - pvname=config["id"], - name=name, - is_setting=True, - ) - self._append( - DelayTime, self.delaystage_both, name="delay_both", is_setting=True - ) - self._append( - DelayTime, self.delaystage_pulse2, name="delay_pulse2", is_setting=True - ) +# self.motor_configuration = { +# "delaystage_both": { +# "id": "SARES23:ESB15", +# }, +# "delaystage_pulse2": { +# "id": "SARES23:ESB1", +# }, +# "wp_both": { +# "id": "SARES23:ESB3", +# }, +# "wp_pulse2": { +# "id": "SARES23:ESB2", +# }, +# } +# for name, config in self.motor_configuration.items(): +# self._append( +# SmaractRecord, +# pvname=config["id"], +# name=name, +# is_setting=True, +# ) +# self._append( +# DelayTime, self.delaystage_both, name="delay_both", is_setting=True +# ) +# self._append( +# DelayTime, self.delaystage_pulse2, name="delay_pulse2", is_setting=True +# ) #namespace.append_obj( @@ -1556,9 +1566,9 @@ class N2jet(Assembly): class Incoupling(Assembly): def __init__(self, name=None): super().__init__(name=name) - self._append(SmaractRecord, "SARES23:ESB11", name="rz", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB13", name="ry", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB10", name="x", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB10", name="ver", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB13", name="hor", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB11", name="x", is_setting=True) self._append(MotorRecord, "SLAAR21-LMOT-M521:MOTOR_1", name="delaystage_eos", is_setting=True,) self._append(DelayTime, self.delaystage_eos, name="delay_eos", is_setting=False, is_display=True) @@ -1585,44 +1595,44 @@ namespace.append_obj( name="jfs", ) -#namespace.append_obj( -# "High_field_thz_chamber", -# name="thc", -# lazy=True, -# module_name="eco.endstations.bernina_sample_environments", - # configuration=["ottifant"], -# configuration=[], -#) - -class Sample_stages(Assembly): - def __init__(self, name=None): - super().__init__(name=name) - self._append(MotorRecord, "SARES20-MF1:MOT_11", name="x", is_setting=True) - self._append(MotorRecord, "SARES20-MF1:MOT_9", name="y", is_setting=True) - namespace.append_obj( - Sample_stages, + "High_field_thz_chamber", + name="thc", lazy=True, - name="sample", + module_name="eco.endstations.bernina_sample_environments", + # configuration=["ottifant"], + configuration=[], ) -class LaserSteering(Assembly): - def __init__(self, name=None): - super().__init__(name=name) - self._append(SmaractRecord, "SARES23:ESB3", name="mirr1_pitch", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB4", name="mirr1_roll", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB14", name="mirr2_pitch", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB12", name="mirr2_roll", is_setting=True) +# class Sample_stages(Assembly): +# def __init__(self, name=None): +# super().__init__(name=name) +# self._append(MotorRecord, "SARES20-MF1:MOT_11", name="x", is_setting=True) +# self._append(MotorRecord, "SARES20-MF1:MOT_9", name="y", is_setting=True) -class THzGeneration(Assembly): - def __init__(self, name=None): - super().__init__(name=name) - self._append(SmaractRecord, "SARES23:LIC16", name="par_x", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB8", name="mirr_x", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB7", name="mirr_z", is_setting=True) - self._append(SmaractRecord, "SARES23:LIC18", name="mirr_ry", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB9", name="mirr_rz", is_setting=True) - self._append(SmaractRecord, "SARES23:LIC15", name="polarizer", is_setting=True) +# namespace.append_obj( +# Sample_stages, +# lazy=True, +# name="sample", +# ) + +# class LaserSteering(Assembly): +# def __init__(self, name=None): +# super().__init__(name=name) +# self._append(SmaractRecord, "SARES23:ESB3", name="mirr1_pitch", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB4", name="mirr1_roll", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB14", name="mirr2_pitch", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB12", name="mirr2_roll", is_setting=True) + +# class THzGeneration(Assembly): +# def __init__(self, name=None): +# super().__init__(name=name) +# self._append(SmaractRecord, "SARES23:LIC16", name="par_x", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB8", name="mirr_x", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB7", name="mirr_z", is_setting=True) +# self._append(SmaractRecord, "SARES23:LIC18", name="mirr_ry", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB9", name="mirr_rz", is_setting=True) +# self._append(SmaractRecord, "SARES23:LIC15", name="polarizer", is_setting=True) class THzVirtualStages(Assembly): def __init__(self, name=None, mx=None, mz=None, px=None, pz=None): @@ -1696,36 +1706,36 @@ class THzVirtualStages(Assembly): -class THz(Assembly): - def __init__(self, name=None): - super().__init__(name=name) - self._append(SmaractRecord, "SARES23:ESB6", name="par_x", is_setting=True) - self._append(MotorRecord, "SARES20-MF1:MOT_10", name="par_y", is_setting=True) - self._append(SmaractRecord, "SARES23:LIC13", name="par_z", is_setting=True) - self._append(SmaractRecord, "SARES23:LIC14", name="par_rx", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB15", name="par_ry", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB1", name="delaystage_thz", is_setting=True,) - self._append(DelayTime, self.delaystage_thz, name="delay_thz", is_setting=False, is_display=True,) - self._append(LaserSteering, name="ir_pointing", is_setting=False) - self._append(THzGeneration, name="generation", is_setting=False) +# class THz(Assembly): +# def __init__(self, name=None): +# super().__init__(name=name) +# self._append(SmaractRecord, "SARES23:ESB6", name="par_x", is_setting=True) +# self._append(MotorRecord, "SARES20-MF1:MOT_10", name="par_y", is_setting=True) +# self._append(SmaractRecord, "SARES23:LIC13", name="par_z", is_setting=True) +# self._append(SmaractRecord, "SARES23:LIC14", name="par_rx", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB15", name="par_ry", is_setting=True) +# self._append(SmaractRecord, "SARES23:ESB1", name="delaystage_thz", is_setting=True,) +# self._append(DelayTime, self.delaystage_thz, name="delay_thz", is_setting=False, is_display=True,) +# self._append(LaserSteering, name="ir_pointing", is_setting=False) +# self._append(THzGeneration, name="generation", is_setting=False) ### Virtual stages ### - self._append( - THzVirtualStages, - name="virtual_stages", - mx=self.generation.mirr_x, - mz=self.generation.mirr_z, - px=self.generation.par_x, - pz = self.par_z, - is_setting=False) + # self._append( + # THzVirtualStages, + # name="virtual_stages", + # mx=self.generation.mirr_x, + # mz=self.generation.mirr_z, + # px=self.generation.par_x, + # pz = self.par_z, + # is_setting=False) -namespace.append_obj( - THz, - lazy=True, - name="thz", -) +# namespace.append_obj( +# THz, +# lazy=True, +# name="thz", +# ) # class THz_in_air(Assembly): # def __init__(self, name=None): @@ -2054,62 +2064,60 @@ namespace.append_obj( ##combined delaystage with phase shifter motion## -class Stage_LXT_Delay(Assembly): - def __init__(self, name=None): - super().__init__(name=name) - self._append( - AdjustableFS, - "/photonics/home/gac-bernina/eco/configuration/p20794_phase_shifter_threshold", - name="thr", - default_value=-280e-12, - is_setting=True, - ) - self._append( - AdjustableFS, - "/photonics/home/gac-bernina/eco/configuration/p20794_phase_shifter_offset", - name="ps0", - default_value=-2.5006914999999344e-08, - is_setting=True, - ) - self._append( - AdjustableFS, - "/photonics/home/gac-bernina/eco/configuration/p20794_delay_stage_offset", - name="dp0", - default_value=0, - is_setting=True, - ) +# class Stage_LXT_Delay(Assembly): +# def __init__(self, delay_adj, delay_adj_offset_fina, name=None): +# super().__init__(name=name) +# self.delay_adj = delay_adj +# self.delay_adj_offset_fina = delay_adj_offset_fina +# self._append( +# AdjustableFS, +# "/photonics/home/gac-bernina/eco/configuration/p21145_phase_shifter_threshold", +# name="thr", +# default_value=-50e-12, +# is_setting=True, +# ) +# self._append( +# AdjustableFS, +# "/photonics/home/gac-bernina/eco/configuration/p21145_phase_shifter_offset", +# name="ps0", +# default_value=9.490000000000003e-09, +# is_setting=True, +# ) +# self._append( +# AdjustableFS, +# self.delay_adj_offset_fina, +# name="dp0", +# default_value=0, +# is_setting=True, +# ) - def get_comb_delay(pd, ps): - ps_rel = ps - self.ps0() - pd_rel = pd - self.dp0() - return ps_rel + pd_rel +# def get_comb_delay(pd, ps): +# ps_rel = ps - self.ps0() +# pd_rel = pd - self.dp0() +# return ps_rel + pd_rel - def set_comb_delay(delay): - if delay > self.thr(): - if np.abs(las.xlt() - self.ps0()) > 50e-15: - ps_pos = self.ps0() - else: - ps_pos = None - pd_pos = self.dp0() + delay - else: - ps_pos = self.ps0() + delay - pd_pos = self.dp0() - return pd_pos, ps_pos +# def set_comb_delay(delay): +# if delay > self.thr(): +# if np.abs(las.xlt() - self.ps0()) > 50e-15: +# ps_pos = self.ps0() +# else: +# ps_pos = None +# pd_pos = self.dp0() + delay +# else: +# ps_pos = self.ps0() + delay +# pd_pos = self.dp0() +# return pd_pos, ps_pos - self._append( - AdjustableVirtual, - [las.delay_pump, las.xlt], - get_comb_delay, - set_comb_delay, - name="delay_combined", - ) +# self._append( +# AdjustableVirtual, +# [self.delay_adj, las.xlt], +# get_comb_delay, +# set_comb_delay, +# name="delay_combined", +# ) +# thz._append(Stage_LXT_Delay, thz.delay_thz, "/photonics/home/gac-bernina/eco/configuration/p21145_delay_stage_offset", name="delay_thz_phase_shifter", is_setting=False, is_display=True,) - -#namespace.append_obj( -# Stage_LXT_Delay, -# name="stage_ps_delay", -# lazy=True, -#) +# thz._append(Stage_LXT_Delay, eos.delay_eos, "/photonics/home/gac-bernina/eco/configuration/p21145_delayeos_stage_offset", name="delay_eos_phase_shifter", is_setting=False, is_display=True,) # # self.combined_delay = AdjustableVirtual( # # [self.delay_thz, self.delay_800_pump], diff --git a/eco/devices_general/wago.py b/eco/devices_general/wago.py index 7ea1388..4c3d9e4 100644 --- a/eco/devices_general/wago.py +++ b/eco/devices_general/wago.py @@ -30,8 +30,9 @@ class AnalogInput(Assembly): self.pvname + ".EGU", name="unit", is_setting=False, - is_display=False, + is_display=True, ) + self.value.unit = self.unit self._append( DetectorPvData, self.pvname + ".RVAL", @@ -83,14 +84,17 @@ class AnalogInput(Assembly): def reset_slope_current_value_to(self,value=1): oslo = self.linear_calibration_slope.get_current_value() ooff = self.linear_calibration_offset.get_current_value() - self.linear_calibration_offset.set_target_value( - ooff/oslo - * self._adj_slope.get_current_value() - * value - ).wait() ooff_raw = ooff / oslo / self._adj_slope.get_current_value() - nslo = value / (self.raw.get_current_value()-ooff_raw) + # print(ooff_raw) + + + nslo = value / (self.raw.get_current_value()+ooff_raw) self.linear_calibration_slope.set_target_value(nslo).wait() + self.linear_calibration_offset.set_target_value( + ooff_raw + * nslo + * self._adj_slope.get_current_value() + ).wait() class WagoAnalogInputs(Assembly): diff --git a/eco/elements/assembly.py b/eco/elements/assembly.py index 61bc11c..de5949b 100644 --- a/eco/elements/assembly.py +++ b/eco/elements/assembly.py @@ -14,6 +14,9 @@ from rich.progress import track from eco import Adjustable, Detector +_initializing_assemblies = [] + + class Collection: def __init__(self, name=None): if name is None: @@ -314,10 +317,24 @@ class Assembly: label = self.alias.get_full_name() + " status\n" return label + self.get_display_str() - def _wait_for_initialisation(self, timeout=2): - for ton, to in self.__dict__.items(): - if isinstance(to, InitialisationWaitable): - to._wait_for_initialisation() + # def _wait_for_initialisation(self, timeout=2): + # for ton, to in self.__dict__.items(): + # try: + # iswaitable = isinstance(to, InitialisationWaitable) + # if iswaitable: + # to._wait_for_initialisation() + # except: + # pass + + def _wait_for_initialisation(self): + for item in self.status_collection.get_list(): + if isinstance(item, Assembly) and (item in _initializing_assemblies): + continue + if isinstance(item, InitialisationWaitable): + if isinstance(item,Assembly): + _initializing_assemblies.append(item) + item._wait_for_initialisation() + def _run_cmd(self, line, silent=True): if silent: diff --git a/eco/endstations/bernina_sample_environments.py b/eco/endstations/bernina_sample_environments.py index 00f2bd1..ff07a03 100644 --- a/eco/endstations/bernina_sample_environments.py +++ b/eco/endstations/bernina_sample_environments.py @@ -43,7 +43,8 @@ class High_field_thz_chamber(Assembly): self.par_out_pos = [35, -9.5] self.motor_configuration = { "rx": { - "id": "SARES23:ESB13", + # "id": "SARES23:ESB13", + "id": "SARES23:ESB6", "pv_descr": "Motor7:1 THz Chamber Rx", "type": 2, "sensor": 1, @@ -52,7 +53,8 @@ class High_field_thz_chamber(Assembly): "kwargs": {"accuracy": 0.01}, }, "x": { - "id": "SARES23:ESB14", + # "id": "SARES23:ESB14", + "id": "SARES23:ESB15", "pv_descr": "Motor7:2 THz Chamber x ", "type": 1, "sensor": 0, @@ -60,7 +62,8 @@ class High_field_thz_chamber(Assembly): "home_direction": "back", }, "z": { - "id": "SARES23:ESB10", + # "id": "SARES23:ESB10", + "id": "SARES23:LIC16", "pv_descr": "Motor6:1 THz Chamber z ", "type": 1, "sensor": 0, @@ -68,7 +71,8 @@ class High_field_thz_chamber(Assembly): "home_direction": "back", }, "ry": { - "id": "SARES23:ESB11", + # "id": "SARES23:ESB11", + "id": "SARES23:LIC15", "pv_descr": "Motor6:2 THz Chamber Ry", "type": 2, "sensor": 1, @@ -76,7 +80,8 @@ class High_field_thz_chamber(Assembly): "home_direction": "back", }, "rz": { - "id": "SARES23:ESB12", + # "id": "SARES23:ESB12", + "id": "SARES23:ESB4", "pv_descr": "Motor6:3 THz Chamber Rz", "type": 2, "sensor": 1, @@ -262,40 +267,45 @@ class Organic_crystal_breadboard(Assembly): self.alias = Alias(name) self.motor_configuration = { - "mirr2_x": { - "id": "-LIC17", + "mir_x": { + # "id": "-LIC17", + "id": ":ESB8", "pv_descr": "Motor8:2 THz mirror x ", "type": 1, "sensor": 13, "speed": 250, "home_direction": "back", }, - "mirr2_rz": { - "id": "-LIC18", + "mir_rz": { + # "id": "-LIC18", + "id": ":ESB9", "pv_descr": "Motor8:3 THz mirror rz ", "type": 1, "sensor": 13, "speed": 250, "home_direction": "back", }, - "mirr2_ry": { - "id": "-ESB1", + "mir_ry": { + # "id": "-ESB1", + "id": ":LIC18", "pv_descr": "Motor3:1 THz mirror ry ", "type": 2, "sensor": 1, "speed": 250, "home_direction": "forward", }, - "mirr2_z": { - "id": "-LIC16", + "mir_z": { + # "id": "-LIC16", + "id": ":ESB7", "pv_descr": "Motor8:1 THz mirror z", "type": 1, "sensor": 13, "speed": 250, "home_direction": "back", }, - "par2_x": { - "id": "-ESB3", + "par_x": { + # "id": "-ESB3", + "id": ":LIC17", "pv_descr": "Motor3:3 THz parabola2 x", "type": 1, "sensor": 0, @@ -303,39 +313,43 @@ class Organic_crystal_breadboard(Assembly): "home_direction": "back", }, "delaystage_thz": { - "id": "-ESB18", + # "id": "-ESB18", + "id": ":ESB1", "pv_descr": "Motor8:3 NIR delay stage", "type": 1, "sensor": 0, "speed": 100, "home_direction": "back", }, - "nir_mirr1_ry": { - "id": "-ESB17", + "nir_m1_ry": { + # "id": "-ESB17", + "id": ":ESB3", "pv_descr": "Motor8:2 near IR mirror 1 ry", "type": 2, "sensor": 1, "speed": 250, "home_direction": "back", }, - "nir_mirr1_rx": { - "id": "-ESB16", + "nir_m1_rx": { + "id": ":ESB16", "pv_descr": "Motor8:1 near IR mirror 1 rx", "type": 2, "sensor": 1, "speed": 250, "home_direction": "back", }, - "nir_mirr2_ry": { - "id": "-ESB9", + "nir_m2_ry": { + # "id": "-ESB9", + "id": ":ESB14", "pv_descr": "Motor5:3 near IR mirror 2 ry", "type": 2, "sensor": 1, "speed": 250, "home_direction": "back", }, - "nir_mirr2_rx": { - "id": "-ESB4", + "nir_m2_rx": { + # "id": ":ESB4", + "id": ":ESB12", "pv_descr": "Motor4:1 near IR mirror 2 rx", "type": 1, "sensor": 13, @@ -343,7 +357,7 @@ class Organic_crystal_breadboard(Assembly): "home_direction": "back", }, "crystal": { - "id": "-ESB2", + "id": ":ESB2", "pv_descr": "Motor3:2 crystal rotation", "type": 2, "sensor": 1, @@ -351,7 +365,7 @@ class Organic_crystal_breadboard(Assembly): "home_direction": "back", }, "wp": { - "id": "-ESB7", + "id": ":ESB7", "pv_descr": "Motor5:1 waveplate rotation", "type": 2, "sensor": 1, @@ -366,7 +380,7 @@ class Organic_crystal_breadboard(Assembly): ### smaract motors ### for name, config in self.motor_configuration.items(): self._append( - SmaractStreamdevice, + SmaractRecord, pvname=Id + config["id"], name=name, is_setting=True, diff --git a/eco/epics/adjustable.py b/eco/epics/adjustable.py index 87f70d6..a9fe229 100644 --- a/eco/epics/adjustable.py +++ b/eco/epics/adjustable.py @@ -33,7 +33,6 @@ class AdjustablePv: element_count=None, unit=None, ): - # alias_fields={"setpv": pvsetname, "readback": pvreadbackname}, # ): self.Id = pvsetname @@ -73,6 +72,15 @@ class AdjustablePv: self._pvhighlim = None self.alias = Alias(name, channel=pvreadbackname, channeltype="CA") + def _wait_for_initialisation(self): + self._pv.wait_for_connection() + if hasattr(self, "_pv_readback") and self._pv_readback: + self._pv_readback.wait_for_connection() + if hasattr(self, "_pv_lowlim") and self._pv_lowlim: + self._pv_lowlim.wait_for_connection() + if hasattr(self, "_pv_highlim") and self._pv_highlim: + self._pv_highlim.wait_for_connection() + def get_current_value(self, readback=True): if readback: currval = self._pvreadback.get() @@ -98,11 +106,15 @@ class AdjustablePv: def change(self, value): if self._pvlowlim: if value < self._pvlowlim.get(): - raise Exception(f'Target value of {self.name} is smaller than limit value!') + raise Exception( + f"Target value of {self.name} is smaller than limit value!" + ) if self._pvhighlim: if self._pvhighlim.get() < value: - raise Exception(f'Target value of {self.name} is higher than limit value!') - + raise Exception( + f"Target value of {self.name} is higher than limit value!" + ) + self._pv.put(value) time.sleep(0.1) while self.get_change_done() == 0: @@ -167,6 +179,11 @@ class AdjustablePvEnum: ) self.alias = Alias(name, channel=self.Id, channeltype="CA") + def _wait_for_initialisation(self): + self._pv.wait_for_connection() + if hasattr(self, "_pv_set") and self._pv_set: + self._pv_set.wait_for_connection() + def validate(self, value): if type(value) is str: return self.PvEnum.__members__[value] diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index a40c05a..cb03ef9 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -182,14 +182,10 @@ class LaserBernina(Assembly): MotorRecord, self.pvname + "-M533:MOT", name="wp_pol", is_setting=True ) - #self._append( - # MotorRecord, self.pvname + "-M534:MOT", name="wp_att", is_setting=True - #) + self._append( + MotorRecord, self.pvname + "-M534:MOT", name="wp_att", is_setting=True + ) - #ad hoc for tyburskiy setup - self._append(SmaractRecord, "SARES23:LIC15", name="wp_att", is_setting=True) - # ad hoc for 500nm setup - # self._append(SmaractRecord, "SARES23:ESB3", name="wp_att", is_setting=True) self._append( diff --git a/eco/timing/event_timing_new_new.py b/eco/timing/event_timing_new_new.py index 55778a5..46f9cd3 100644 --- a/eco/timing/event_timing_new_new.py +++ b/eco/timing/event_timing_new_new.py @@ -301,31 +301,36 @@ class EvrPulser(Assembly): is_setting=True, ) self.description = EpicsString(pv_base + "-Name-I") - self._append( - AdjustableVirtual, - [self._eventcode.frequency], - lambda x: x, - lambda x: x, - name="frequency", - ) - self._append( - AdjustableVirtual, - [self._eventcode.delay], - lambda x: x, - lambda x: x, - name="delay_eventcode", - ) - self._append( - AdjustableVirtual, - [self.delay_pulser], - lambda tp: self.delay_eventcode.get_current_value() + tp, - lambda x: x - self.delay_eventcode.get_current_value(), - name="delay", - ) + + if True: #self._eventcode is not None: + self._append( + AdjustableVirtual, + [self._eventcode.frequency], + lambda x: x, + lambda x: x, + name="frequency", + ) + self._append( + AdjustableVirtual, + [self._eventcode.delay], + lambda x: x, + lambda x: x, + name="delay_eventcode", + ) + self._append( + AdjustableVirtual, + [self.delay_pulser], + lambda tp: self.delay_eventcode.get_current_value() + tp, + lambda x: x - self.delay_eventcode.get_current_value(), + name="delay", + ) @property def _eventcode(self): - return self._event_master.event_codes[self.eventcode.get_current_value()] + try: + return self._event_master.event_codes[self.eventcode.get_current_value()] + except KeyError: + return None class DummyPulser(Assembly): diff --git a/eco/timing/lasertiming_edwin.py b/eco/timing/lasertiming_edwin.py index 1b33351..02d75c5 100644 --- a/eco/timing/lasertiming_edwin.py +++ b/eco/timing/lasertiming_edwin.py @@ -219,6 +219,14 @@ class XltEpics(Assembly): is_display=True, unit="ps", ) + # self._append( + # AdjustablePvEnum, + # self.pvname + ":MODE_SET1", + # pvname_set = self.pvname + ':MODESELECT', + # name="reference_mode", + # is_setting=True, + # is_display=True, + # ) self._append( AdjustablePvEnum, self.pvname + ":SHOTDELAY", diff --git a/eco/utilities/config.py b/eco/utilities/config.py index 677ef8d..28b42a7 100644 --- a/eco/utilities/config.py +++ b/eco/utilities/config.py @@ -1,6 +1,7 @@ import json import importlib from pathlib import Path +from eco.elements.protocols import InitialisationWaitable import sys from time import time from colorama import Fore as _color @@ -298,7 +299,11 @@ class Namespace(Assembly): # sys.stdout.flush() starttime = time() try: - dir(self.get_obj(name)) + titem = self.get_obj(name) + if isinstance(titem, InitialisationWaitable): + titem._wait_for_initialisation() + else: + dir(titem) if verbose: print( From 10fc9f4c18933689a5a6d52b6e9722285262279e Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Wed, 5 Jul 2023 12:32:28 +0200 Subject: [PATCH 42/52] start fixing xlt --- eco/bernina/bernina.py | 58 +++++++------- eco/loptics/bernina_laser.py | 3 +- eco/timing/lasertiming_edwin.py | 136 ++++++++++++++++++++++++++------ eco/utilities/recspace.py | 4 +- 4 files changed, 145 insertions(+), 56 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index f724691..3bf2acf 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -1344,22 +1344,22 @@ namespace.append_obj( module_name="eco.devices_general.cameras_ptz", ) -#namespace.append_obj( -# "BerninaInlineMicroscope", -# pvname_camera="SARES20-CAMS142-M3", -# lazy=True, -# name="samplecam_inline", -# module_name="eco.microscopes", -#) - namespace.append_obj( - "CameraBasler", - "SARES20-CAMS142-C1", - lazy=True, - name="samplecam_front", - module_name="eco.microscopes", + "BerninaInlineMicroscope", + pvname_camera="SARES20-CAMS142-M3", + lazy=True, + name="samplecam_inline", + module_name="eco.microscopes", ) +# namespace.append_obj( +# "CameraBasler", +# "SARES20-CAMS142-C1", +# lazy=True, +# name="samplecam_front", +# module_name="eco.microscopes", +# ) + #namespace.append_obj( # "MicroscopeMotorRecord", # pvname_camera="SARES20-CAMS142-C1", @@ -1386,21 +1386,21 @@ namespace.append_obj( name="samplecam_sideview", module_name="eco.devices_general.cameras_swissfel", ) -namespace.append_obj( - "CameraBasler", - "SARES20-CAMS142-C2", - lazy=True, - name="samplecam_back_racks", - module_name="eco.devices_general.cameras_swissfel", -) +# namespace.append_obj( +# "CameraBasler", +# "SARES20-CAMS142-C2", +# lazy=True, +# name="samplecam_back_racks", +# module_name="eco.devices_general.cameras_swissfel", +# ) -namespace.append_obj( - "CameraBasler", - "SARES20-CAMS142-C3", - lazy=True, - name="samplecam_back_door", - module_name="eco.devices_general.cameras_swissfel", -) +# namespace.append_obj( +# "CameraBasler", +# "SARES20-CAMS142-C3", +# lazy=True, +# name="samplecam_back_door", +# module_name="eco.devices_general.cameras_swissfel", +# ) @@ -1468,7 +1468,7 @@ namespace.append_obj( Id="SARES23", ) -from ..epics.adjustable import AdjustablePv +from ..epics.adjustable import AdjustablePv, AdjustablePvEnum # class Double_Pulse_Pump(Assembly): @@ -1571,6 +1571,8 @@ class Incoupling(Assembly): self._append(SmaractRecord, "SARES23:ESB11", name="x", is_setting=True) self._append(MotorRecord, "SLAAR21-LMOT-M521:MOTOR_1", name="delaystage_eos", is_setting=True,) self._append(DelayTime, self.delaystage_eos, name="delay_eos", is_setting=False, is_display=True) + self._append(AdjustablePvEnum, "SLAAR21-LDIO-LAS6991:SET_BO02", name='eos_is_shut', is_setting=True) + namespace.append_obj( Incoupling, diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index cb03ef9..e8a7616 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -6,7 +6,7 @@ from ..elements.adjustable import AdjustableMemory, AdjustableVirtual, Adjustabl from ..epics.adjustable import AdjustablePv, AdjustablePvEnum from ..epics.detector import DetectorPvData from ..devices_general.detectors import DetectorVirtual -from ..timing.lasertiming_edwin import XltEpics +from ..timing.lasertiming_edwin import XltEpics, LaserRateControl import colorama import datetime from pint import UnitRegistry @@ -236,6 +236,7 @@ class LaserBernina(Assembly): # self._append( # DelayTime, self.delaystage_pump, name="delay_pump", is_setting=True # ) + self._append(LaserRateControl, name="rate", is_setting=True, is_display="recursive") self._append(XltEpics, name="xlt", is_setting=True, is_display="recursive") # Upstairs, Laser 1 LAM # self._append( diff --git a/eco/timing/lasertiming_edwin.py b/eco/timing/lasertiming_edwin.py index 02d75c5..d5f992d 100644 --- a/eco/timing/lasertiming_edwin.py +++ b/eco/timing/lasertiming_edwin.py @@ -189,7 +189,7 @@ class XltEpics(Assembly): DetectorPvData, "SLAAR-LGEN:DLY_OFFS2", unit="ps", - name="delay_user_rb", + name="delay_dial_rb", is_setting=False, is_display=False, ) @@ -202,12 +202,12 @@ class XltEpics(Assembly): name="offset", unit="s", is_setting=False, - is_display=True, + is_display=False, ) self._append( DetectorVirtual, - [self.delay_user_rb], - lambda dialrb: dialrb * 1e-6, + [self.delay_dial_rb, self.offset], + lambda dialrb,offset: dialrb * 1e-6 - offset, unit="s", name="readback", ) @@ -219,6 +219,25 @@ class XltEpics(Assembly): is_display=True, unit="ps", ) + self._append( + AdjustablePv, + self.pvname + ":LONG_DELAY_THRESH", + name="_long_delay_threshold", + is_setting=True, + is_display=False, + unit="ps", + ) + self._append( + AdjustableVirtual, + [self._long_delay_threshold], + lambda offset: offset * 1e-12, + lambda offset: offset / 1e-12, + name="long_delay_threshold", + unit="s", + is_setting=True, + is_display=True, + ) + # self._append( # AdjustablePvEnum, # self.pvname + ":MODE_SET1", @@ -265,7 +284,7 @@ class XltEpics(Assembly): self._append( AdjustablePv, self.pvname + ":DELAY", - name="_set_dial_delay_value", + name="_set_user_delay_value", is_setting=False, is_display=False, ) @@ -284,23 +303,8 @@ class XltEpics(Assembly): is_setting=True, is_display=True, ) - self._append( - AdjustablePv, - self.pvname + ":LONG_DELAY_THRESH", - name="_long_delay_threshold", - is_setting=True, - is_display=False, - ) - self._append( - AdjustableVirtual, - [self._long_delay_threshold], - lambda offset: offset * 1e-12, - lambda offset: offset / 1e-12, - name="long_delay_threshold", - unit="s", - is_setting=True, - is_display=True, - ) + + # self._append( # DetectorPvData, # "SLAAR-LGEN:DLY_OFFS2", @@ -351,8 +355,8 @@ class XltEpics(Assembly): if is_phasshift: self.waiting_for_change.add_callback(callback=set_is_stopped) - self._set_dial_delay_value.set_target_value( - (value - self.offset.get_current_value()) / 1e-12 + self._set_user_delay_value.set_target_value( + (value) / 1e-12 ) if not is_phasshift: time.sleep(evr_wait_time) @@ -372,7 +376,7 @@ class XltEpics(Assembly): ) def reset_current_value_to(self, value): - self.offset.set_target_value((self.get_current_dial_value() - value)).wait() + self.offset.set_target_value(self.offset.get_current_value() + self.get_current_value() - value).wait() # caqtdm -noMsg -macro S=SLAAR02-LTIM-PDLY /sf/laser/config/qt/SLAAR02-L-SET_DELAY.ui @@ -380,3 +384,85 @@ class XltEpics(Assembly): self._run_cmd( f"caqtdm -noMsg -macro S=SLAAR02-LTIM-PDLY /sf/laser/config/qt/SLAAR02-L-SET_DELAY.ui" ) + +@spec_convenience +@tweak_option +@value_property +class LaserRateControl(Assembly): + def __init__(self, pvname="SLAAR02-LTIM-PDLY", name=None): + super().__init__(name=name) + self.settings_collection.append(self, force=True) + self.pvname = pvname + # self.settings_collection.append(self, force=True) + # self.status_collection.append(self, force=True) + # self.display_collection.append(self, force=True) + self._append( + AdjustablePvEnum, + self.pvname + ":ONEINN_MODE", + name="reference_mode", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePv, + "SIN-TIMAST-TMA:Evt-22-Freq-SP", + name="laser_frequency", + unit="Hz", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePvEnum, + self.pvname + ":SHOTDELAY", + name="oscillator_pulse_offset", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePvEnum, + self.pvname + ":SHOTMOFFS_ENA", + name="modulo_offset_mode", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePvEnum, + self.pvname + ":USE_EXT_EVT", + name="use_ext_reference_event", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePv, + self.pvname + ":ALT_EXT_EVT", + name="ext_reference_event", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePv, + self.pvname + ":P_RATIO", + name="ref_pattern_len", + is_setting=True, + is_display=True, + ) + + + # self._append( + # DetectorPvData, + # "SLAAR-LGEN:DLY_OFFS2", + # name="delay_dial", + # is_setting=False, + # is_display=True, + # ) + + # self._delay_dial_rb = PV("SLAAR-LGEN:DLY_OFFS2") + # self.alias.append( + # Alias("delay_dial_rb", "SLAAR-LGEN:DLY_OFFS2", channeltype="CA") + # ) + + + def gui(self): + self._run_cmd( + f"caqtdm -noMsg -macro S=SLAAR02-LTIM-PDLY /sf/laser/config/qt/SLAAR02-L-SET_DELAY.ui" + ) \ No newline at end of file diff --git a/eco/utilities/recspace.py b/eco/utilities/recspace.py index 1b34f8a..858ca63 100644 --- a/eco/utilities/recspace.py +++ b/eco/utilities/recspace.py @@ -70,7 +70,7 @@ class Crystals(Assembly): name = input( "Please choose a name for your crystal (no spaces or other special characters):" ) - specials = np.array([" ", "/", "(", ")", "[", "]"]+list(self.crystal_list.keys())) + specials = np.array([".", " ", "/", "(", ")", "[", "]"]+list(self.crystal_list().keys())) in_name = np.array([s in name for s in specials]) if np.any(in_name): raise Exception( @@ -195,7 +195,7 @@ class DiffGeometryYou(Assembly): f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_unit_cell", name="unit_cell", default_value={ - "name": name, + "name": "", "a": 1, "b": 1, "c": 1, From 76514d59f96d7e1331fe90e514748adcce7986cd Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Thu, 6 Jul 2023 14:07:34 +0200 Subject: [PATCH 43/52] power supplies wiener --- eco/bernina/bernina.py | 58 ++++++++++++++++++ eco/devices_general/powersockets.py | 6 +- eco/endstations/bernina_robot.py | 9 +++ .../bernina_sample_environments.py | 6 +- eco/timing/lasertiming_edwin.py | 60 +------------------ 5 files changed, 76 insertions(+), 63 deletions(-) create mode 100644 eco/endstations/bernina_robot.py diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 3bf2acf..1345291 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -2,6 +2,7 @@ import json from pathlib import Path from threading import Thread from eco.acquisition.scan import NumpyEncoder +from eco.devices_general.powersockets import MpodModule from eco.elements.adjustable import AdjustableFS from eco.elements.adjustable import AdjustableVirtual from eco.loptics.bernina_experiment import DelayCompensation @@ -785,6 +786,54 @@ namespace.append_obj( lazy=True, ) +namespace.append_obj( + "DetectorRobot", + JF_detector_id='JF01T03V01', + JF_detector_name='det_diff', + pgroup_adj=config_bernina.pgroup, + module_name="eco.endstations.bernina_robot", + name='robot', +) + +namespace.append_obj( + "MpodModule", + "SARES21-CPCL-PS7071", + [1,2,3,4], + ['ch1','ch2','ch3','ch4'], + module_string='LV_OMPV_1', + name="power_LV_patch1", + module_name="eco.devices_general.powersockets", +) + +namespace.append_obj( + "MpodModule", + "SARES21-CPCL-PS7071", + [5,6,7,8], + ['ch1','ch2','ch3','ch4'], + module_string='LV_OMPV_1', + name="power_LV_patch2", + module_name="eco.devices_general.powersockets", +) + +namespace.append_obj( + "MpodModule", + "SARES21-CPCL-PS7071", + [1,2,3,4], + ['ch1','ch2','ch3','ch4'], + module_string='HV_EHS_3', + name="power_HV_patch1", + module_name="eco.devices_general.powersockets", +) + +namespace.append_obj( + "MpodModule", + "SARES21-CPCL-PS7071", + [5,6,7,8], + ['ch1','ch2','ch3','ch4'], + module_string='HV_EHS_3', + name="power_HV_patch2", + module_name="eco.devices_general.powersockets", +) ### draft new epics daq ### # namespace.append_obj( @@ -1572,6 +1621,14 @@ class Incoupling(Assembly): self._append(MotorRecord, "SLAAR21-LMOT-M521:MOTOR_1", name="delaystage_eos", is_setting=True,) self._append(DelayTime, self.delaystage_eos, name="delay_eos", is_setting=False, is_display=True) self._append(AdjustablePvEnum, "SLAAR21-LDIO-LAS6991:SET_BO02", name='eos_is_shut', is_setting=True) + self._append(DigitizerIoxosBoxcarChannel,"SARES20-LSCP9-FNS:CH1", + name=f"signal_pol0", + is_setting=True, + ) + self._append(DigitizerIoxosBoxcarChannel,"SARES20-LSCP9-FNS:CH3", + name=f"signal_pol1", + is_setting=True, + ) namespace.append_obj( @@ -1602,6 +1659,7 @@ namespace.append_obj( name="thc", lazy=True, module_name="eco.endstations.bernina_sample_environments", + illumination_mpod = [{'pvbase':'SARES21-CPCL-PS7071' ,'channel_number':5 ,'module_string':'LV_OMPV_1' ,'name': 'illumination'}], # configuration=["ottifant"], configuration=[], ) diff --git a/eco/devices_general/powersockets.py b/eco/devices_general/powersockets.py index 84ef886..a4ebeb5 100644 --- a/eco/devices_general/powersockets.py +++ b/eco/devices_general/powersockets.py @@ -128,7 +128,7 @@ class MpodChannel(Assembly): return self.on.set_target_value(*args,**kwargs) class MpodModule(Assembly): - def __init__(self,pvbase,N_channels=8, module_string='LV_OMPV_1', name=None): + def __init__(self,pvbase,channelnumbers, channelnames, module_string='LV_OMPV_1', name=None): super().__init__(name=name) - for n in range(1,N_channels+1): - self._append(MpodChannel,pvbase,channel_number=n, module_string=module_string,name=f'ch{n}') \ No newline at end of file + for channelnumber,channelname in zip(channelnumbers,channelnames): + self._append(MpodChannel,pvbase,channel_number=channelnumber, module_string=module_string,name=channelname) \ No newline at end of file diff --git a/eco/endstations/bernina_robot.py b/eco/endstations/bernina_robot.py new file mode 100644 index 0000000..09b03dd --- /dev/null +++ b/eco/endstations/bernina_robot.py @@ -0,0 +1,9 @@ +from eco import Assembly +from eco.detector.jungfrau import Jungfrau + +class DetectorRobot(Assembly): + def __init__(self,JF_detector_id=None, JF_detector_name='det_diff', name='robot', pgroup_adj=None): + super().__init__(name=name) + self._append(Jungfrau,JF_detector_id,pgroup_adj=pgroup_adj, name=JF_detector_name) + + \ No newline at end of file diff --git a/eco/endstations/bernina_sample_environments.py b/eco/endstations/bernina_sample_environments.py index ff07a03..8f8482f 100644 --- a/eco/endstations/bernina_sample_environments.py +++ b/eco/endstations/bernina_sample_environments.py @@ -1,3 +1,4 @@ +from eco.devices_general.powersockets import MpodChannel import sys sys.path.append("..") @@ -36,7 +37,7 @@ def addSmarActRecordToSelf(self, Id=None, name=None, **kwargs): class High_field_thz_chamber(Assembly): - def __init__(self, name=None, alias_namespace=None, configuration=[]): + def __init__(self, name=None, alias_namespace=None, configuration=[], illumination_mpod = None): super().__init__(name=name) self.name = name self.alias = Alias(name) @@ -170,6 +171,9 @@ class High_field_thz_chamber(Assembly): is_display=True, is_setting=True, ) + if illumination_mpod: + for illu in illumination_mpod: + self._append(MpodChannel,illu['pvbase'], illu['channel_number'], module_string=illu['module_string'], name=illu['name']) def moveout(self): change_in_pos = str( diff --git a/eco/timing/lasertiming_edwin.py b/eco/timing/lasertiming_edwin.py index d5f992d..88a787a 100644 --- a/eco/timing/lasertiming_edwin.py +++ b/eco/timing/lasertiming_edwin.py @@ -237,50 +237,6 @@ class XltEpics(Assembly): is_setting=True, is_display=True, ) - - # self._append( - # AdjustablePvEnum, - # self.pvname + ":MODE_SET1", - # pvname_set = self.pvname + ':MODESELECT', - # name="reference_mode", - # is_setting=True, - # is_display=True, - # ) - self._append( - AdjustablePvEnum, - self.pvname + ":SHOTDELAY", - name="oscillator_pulse_offset", - is_setting=True, - is_display=True, - ) - self._append( - AdjustablePvEnum, - self.pvname + ":SHOTMOFFS_ENA", - name="modulo_offset_mode", - is_setting=True, - is_display=True, - ) - self._append( - AdjustablePvEnum, - self.pvname + ":ONEINN_MODE", - name="reference_mode", - is_setting=True, - is_display=True, - ) - self._append( - AdjustablePvEnum, - self.pvname + ":USE_EXT_EVT", - name="use_ext_reference_event", - is_setting=True, - is_display=True, - ) - self._append( - AdjustablePv, - self.pvname + ":ALT_EXT_EVT", - name="ext_reference_event", - is_setting=True, - is_display=True, - ) self._append( AdjustablePv, self.pvname + ":DELAY", @@ -288,21 +244,7 @@ class XltEpics(Assembly): is_setting=False, is_display=False, ) - self._append( - AdjustablePv, - self.pvname + ":P_RATIO", - name="ref_pattern_len", - is_setting=True, - is_display=True, - ) - self._append( - AdjustablePv, - "SIN-TIMAST-TMA:Evt-22-Freq-SP", - name="laser_frequency", - unit="Hz", - is_setting=True, - is_display=True, - ) + # self._append( From a3672aa4db045c12cf684ee230d5d9adc0a9e6a9 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Wed, 12 Jul 2023 22:27:34 +0200 Subject: [PATCH 44/52] added pipeline --- eco/acquisition/checkers.py | 2 +- eco/bernina/bernina.py | 111 +++-- eco/bernina/config.py | 22 +- eco/devices_general/pipelines_swissfel.py | 468 ++++++++++++++++++ eco/elements/adj_obj.py | 49 +- eco/elements/adjustable.py | 16 +- eco/elements/detector.py | 17 +- .../bernina_sample_environments.py | 23 +- eco/timing/timing_diag.py | 2 + eco/utilities/elog_scilog.py | 102 ++++ eco/utilities/swissfel_data_files.py | 12 + eco/xdiagnostics/intensity_monitors.py | 4 + 12 files changed, 767 insertions(+), 61 deletions(-) create mode 100644 eco/devices_general/pipelines_swissfel.py create mode 100755 eco/utilities/elog_scilog.py create mode 100644 eco/utilities/swissfel_data_files.py diff --git a/eco/acquisition/checkers.py b/eco/acquisition/checkers.py index 60d8365..2551c95 100644 --- a/eco/acquisition/checkers.py +++ b/eco/acquisition/checkers.py @@ -7,7 +7,7 @@ from ..elements.assembly import Assembly class CheckerCA(Assembly): - def __init__(self, pvname, thresholds, required_fraction, name=None): + def __init__(self, pvname=None, thresholds=None, required_fraction=None, name=None): super().__init__(name=name) self._append(DetectorPvDataStream, pvname, name="monitor") self._append( diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 1345291..98c3ff6 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -336,6 +336,30 @@ namespace.append_obj( lazy=True, ) +namespace.append_obj( + "SolidTargetDetectorPBPS", + "SAROP21-PBPS133", + # channel_xpos="SLAAR21-LTIM01-EVR0:CALCX", + # channel_ypos="SLAAR21-LTIM01-EVR0:CALCY", + # channel_intensity="SLAAR21-LTIM01-EVR0:CALCI", + # diode_channels_raw={ + # "up": "SLAAR21-LSCP1-FNS:CH6:VAL_GET", + # "down": "SLAAR21-LSCP1-FNS:CH7:VAL_GET", + # "left": "SLAAR21-LSCP1-FNS:CH4:VAL_GET", + # "right": "SLAAR21-LSCP1-FNS:CH5:VAL_GET", + # }, + # calibration_records={ + # "intensity": "SLAAR21-LTIM01-EVR0:CALCI", + # "xpos": "SLAAR21-LTIM01-EVR0:CALCX", + # "ypos": "SLAAR21-LTIM01-EVR0:CALCY", + # }, + name="mon_opt_new", + module_name="eco.xdiagnostics.intensity_monitors", + pipeline_computation='SAROP21-PBPS133_proc', + lazy=True, +) + + namespace.append_obj( "Pprm", "SARFE10-PPRM064", @@ -795,45 +819,45 @@ namespace.append_obj( name='robot', ) -namespace.append_obj( - "MpodModule", - "SARES21-CPCL-PS7071", - [1,2,3,4], - ['ch1','ch2','ch3','ch4'], - module_string='LV_OMPV_1', - name="power_LV_patch1", - module_name="eco.devices_general.powersockets", -) - -namespace.append_obj( - "MpodModule", - "SARES21-CPCL-PS7071", - [5,6,7,8], - ['ch1','ch2','ch3','ch4'], - module_string='LV_OMPV_1', - name="power_LV_patch2", - module_name="eco.devices_general.powersockets", -) - -namespace.append_obj( - "MpodModule", - "SARES21-CPCL-PS7071", - [1,2,3,4], - ['ch1','ch2','ch3','ch4'], - module_string='HV_EHS_3', - name="power_HV_patch1", - module_name="eco.devices_general.powersockets", -) - -namespace.append_obj( - "MpodModule", - "SARES21-CPCL-PS7071", - [5,6,7,8], - ['ch1','ch2','ch3','ch4'], - module_string='HV_EHS_3', - name="power_HV_patch2", - module_name="eco.devices_general.powersockets", -) +#namespace.append_obj( +# "MpodModule", +# "SARES21-CPCL-PS7071", +# [1,2,3,4], +# ['ch1','ch2','ch3','ch4'], +# module_string='LV_OMPV_1', +# name="power_LV_patch1", +# module_name="eco.devices_general.powersockets", +#) +# +#namespace.append_obj( +# "MpodModule", +# "SARES21-CPCL-PS7071", +# [5,6,7,8], +# ['ch1','ch2','ch3','ch4'], +# module_string='LV_OMPV_1', +# name="power_LV_patch2", +# module_name="eco.devices_general.powersockets", +#) +# +#namespace.append_obj( +# "MpodModule", +# "SARES21-CPCL-PS7071", +# [1,2,3,4], +# ['ch1','ch2','ch3','ch4'], +# module_string='HV_EHS_3', +# name="power_HV_patch1", +# module_name="eco.devices_general.powersockets", +#) +# +#namespace.append_obj( +# "MpodModule", +# "SARES21-CPCL-PS7071", +# [5,6,7,8], +# ['ch1','ch2','ch3','ch4'], +# module_string='HV_EHS_3', +# name="power_HV_patch2", +# module_name="eco.devices_general.powersockets", +#) ### draft new epics daq ### # namespace.append_obj( @@ -1335,6 +1359,14 @@ def _create_metadata_structure_start_scan( # <<<< Extract for run table and elog callbacks_start_scan.append(_create_metadata_structure_start_scan) +namespace.append_obj( + 'CheckerCA', + module_name='eco.acquisition.checkers', + pvname='SLAAR21-LTIM01-EVR0:CALCI', + thresholds=[0.2,10], + required_fraction=0.6, + name="checker", +) namespace.append_obj( "Scans", @@ -1660,6 +1692,7 @@ namespace.append_obj( lazy=True, module_name="eco.endstations.bernina_sample_environments", illumination_mpod = [{'pvbase':'SARES21-CPCL-PS7071' ,'channel_number':5 ,'module_string':'LV_OMPV_1' ,'name': 'illumination'}], + helium_control_valve = {'pvbase':'SARES21-CPCL-PS7071' ,'channel_number':4 ,'module_string':'LV_OMPV_1' ,'name': 'helium_control_valve'}, # configuration=["ottifant"], configuration=[], ) diff --git a/eco/bernina/config.py b/eco/bernina/config.py index 101683b..d72d544 100755 --- a/eco/bernina/config.py +++ b/eco/bernina/config.py @@ -406,17 +406,17 @@ components = [ # "default_file_path": None, # }, # }, - { - "args": [ - config["checker_PV"], - config["checker_thresholds"], - config["checker_fractionInThreshold"], - ], #'SARFE10-PBPG050:HAMP-INTENSITY-CAL',[60,700],.7], - "name": "checker", - "desc": "checker functions for data acquisition", - "type": "eco.acquisition.checkers:CheckerCA", - "kwargs": {}, - }, + #{ + # "args": [ + # config["checker_PV"], + # config["checker_thresholds"], + # config["checker_fractionInThreshold"], + # ], #'SARFE10-PBPG050:HAMP-INTENSITY-CAL',[60,700],.7], + # "name": "checker", + # "desc": "checker functions for data acquisition", + # "type": "eco.acquisition.checkers:CheckerCA", + # "kwargs": {}, + #}, # { # "args": [ # "SARES20-LSCP9-FNS:CH1:VAL_GET", diff --git a/eco/devices_general/pipelines_swissfel.py b/eco/devices_general/pipelines_swissfel.py new file mode 100644 index 0000000..29209e0 --- /dev/null +++ b/eco/devices_general/pipelines_swissfel.py @@ -0,0 +1,468 @@ +from cam_server import CamClient, PipelineClient + +from eco.devices_general.utilities import Changer +from eco.elements.adj_obj import AdjustableObject, DetectorObject +from eco.elements.detector import DetectorGet +from ..aliases import Alias, append_object_to_object +from ..elements.adjustable import AdjustableVirtual, AdjustableGetSet, value_property +from ..epics.adjustable import AdjustablePv, AdjustablePvEnum +from ..elements.assembly import Assembly +from .motors import MotorRecord +import sys +from pathlib import Path +import time + +sys.path.append("/sf/bernina/config/src/python/sf_databuffer/") +import bufferutils + +CAM_CLIENT = None +PIPELINE_CLIENT = None + + +def get_camclient(): + global CAM_CLIENT + if not CAM_CLIENT: + CAM_CLIENT = CamClient() + return CAM_CLIENT + + +def get_pipelineclient(): + global PIPELINE_CLIENT + if not PIPELINE_CLIENT: + PIPELINE_CLIENT = PipelineClient() + return PIPELINE_CLIENT + + +@value_property +class Pipeline(Assembly): + def __init__(self, pipeline_name, name=None, camserver_group=None): + super().__init__(name=name) + self.pipeline_name = pipeline_name + self.camserver_group = camserver_group + self._append(AdjustableGetSet, + self._get_config, + self._set_config, + cache_get_seconds =.05, + precision=0, + check_interval=None, + name='_config', + is_setting=False, + is_display=False) + + self._append(AdjustableObject, self._config, name='config',is_setting=True, is_display='recursive') + self._append(DetectorGet, self._get_info, cache_get_seconds =.05, name='_info', is_setting=False, is_display=False) + self._append(DetectorObject, self._info, name='info', is_display='recursive', is_setting=False) + + + # @property + # def cc(self): + # return get_camclient() + + @property + def pc(self): + return get_pipelineclient() + + def _get_config(self): + return self.pc.get_pipeline_config(self.pipeline_name) + + def _set_config(self, value, hold=False): + return Changer( + target=value, + changer=lambda v: self.pc.set_pipeline_config(self.pipeline_name, v), + hold=hold, + ) + + def _get_info(self, reject_kws = ['config']): + info = self.pc.get_instance_info(self.pipeline_name) + for rkw in reject_kws: + info.pop(rkw) + return info + + def _get_stream(self): + return self.pc.get_instance_stream(self.pipeline_name) + + + + # ### convenience functions ### + # def set_alias(self, alias=None): + # """creates an alias in the camera config on the server. If no alias is provided, it defaults to the camera name""" + # if not alias: + # alias = self.camserver_alias + # self.set_config_fields({"alias": [alias.upper()]}) + + # def set_group(self, group=None): + # """creates an alias in the camera config on the server. If no alias is provided, it defaults to the camera name""" + # if not group: + # group = self.camserver_group + # self.set_config_fields({"group": group}) + + def restart_pipeline(self): + base_directory = "/sf/bernina/config/src/python/sf_databuffer/" + label = self.pipeline_name + + policies = bufferutils.read_files(base_directory / Path("policies"), "policies") + sources = bufferutils.read_files(base_directory / Path("sources"), "sources") + sources_new = sources.copy() + + # Only for debugging purposes + labeled_sources = bufferutils.get_labeled_sources(sources_new, label) + for s in labeled_sources: + bufferutils.logging.info(f"Restarting {s['stream']}") + + sources_new = bufferutils.remove_labeled_source(sources_new, label) + + # Stopping the removed source(s) + bufferutils.update_sources_and_policies(sources_new, policies) + + # Starting the source(s) again + bufferutils.update_sources_and_policies(sources, policies) + + def stop(self): + self.pc.stop_instance(self.pipeline_name) + + # def set_cross(self, x, y, x_um_per_px=None, y_um_per_px=None): + # """set x and y position of the refetence marker on a camera px/um calibration is conserved if no new value is given""" + # calib = self.get_current_value()["camera_calibration"] + # if calib: + # if not x_um_per_px: + # x_um_per_px = calib["reference_marker_width"] / abs( + # calib["reference_marker"][2] - calib["reference_marker"][0] + # ) + # if not y_um_per_px: + # y_um_per_px = calib["reference_marker_height"] / abs( + # calib["reference_marker"][3] - calib["reference_marker"][1] + # ) + # else: + # calib = {} + # x_um_per_px = 1 + # y_um_per_px = 1 + + # calib["reference_marker"] = [x - 1, y - 1, x + 1, y + 1] + # calib["reference_marker_width"] = 2 * x_um_per_px + # calib["reference_marker_height"] = 2 * y_um_per_px + # self.set_config_fields(fields={"camera_calibration": calib}) + + # def set_config_fields_multiple_cams(self, conditions, fields): + # """ + # conditions is a dictionary holding the conditions to select a subset of cameras, e.g. {"group": Bernina} + # fields is a dictionary containing the keys and values that should be updated, e.g. fields={'alias': ['huhu', 'duda']} + # """ + # cams = { + # cam: self.cc.get_camera_config(cam) + # for cam in self.cc.get_cameras() + # if not "jungfrau" in cam + # } + # cams_selected = {} + # for cam, cfg in cams.items(): + # try: + # if all([value in cfg[key] for key, value in conditions.items()]): + # cfg.update(fields) + # self.cc.set_camera_config(cam, cfg) + # cams_selected[cam] = cfg + # except Exception as e: + # print(f"{type(e)} {e} in cam {cam}") + # return cams_selected + + # def clear_all_bernina_aliases(self, verbose=True): + # cams_selected = self.set_config_fields_multiple_cams( + # conditions={"group": "Bernina"}, fields={"alias": []} + # ) + # if verbose: + # print(f"Reset alias of {len(cams_selected)} cameras") + # print(cams_selected.keys()) + + # def __repr__(self): + # s = f"**Camera Server Config {self.pipeline_name} with Alias {self.name}**\n" + # for key, item in self.get_current_value().items(): + # s += f"{key:20} : {item}\n" + # return s + + +class CameraBasler(Assembly): + def __init__(self, pvname, camserver_alias=None, name=None, camserver_group=None): + super().__init__(name=name) + self.pvname = pvname + if not camserver_alias: + camserver_alias = self.alias.get_full_name() + f" ({pvname})" + self._append( + Pipeline, + self.pvname, + camserver_alias=camserver_alias, + camserver_group=camserver_group, + name="config_cs", + is_display=False, + ) + self.config_cs.set_alias() + if camserver_group is not None: + self.config_cs.set_group() + self._append( + AdjustablePvEnum, + self.pvname + ":INIT", + name="initialize", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePvEnum, + self.pvname + ":CAMERASTATUS", + name="running", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + self.pvname + ":BOARD", + name="board_no", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + self.pvname + ":SERIALNR", + name="serial_no", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + self.pvname + ":EXPOSURE", + name="_exposure_time", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePvEnum, + self.pvname + ":ACQMODE", + name="_acq_mode", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePvEnum, + self.pvname + ":RECMODE", + name="_req_mode", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePvEnum, + self.pvname + ":STOREMODE", + name="_store_mode", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + self.pvname + ":BINX", + name="_binx", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + self.pvname + ":BINY", + name="_biny", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + self.pvname + ":REGIONX_START", + name="_roixmin", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + self.pvname + ":REGIONX_END", + name="_roixmax", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + self.pvname + ":REGIONY_START", + name="_roiymin", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePv, + self.pvname + ":REGIONY_END", + name="_roiymax", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePvEnum, + self.pvname + ":SET_PARAM", + name="_set_parameters", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePvEnum, + self.pvname + ":TRIGGER", + name="trigger_on", + is_setting=True, + is_display=True, + ) + self._append( + AdjustablePv, + self.pvname + ":AMPGAIN", + name="_gain", + is_setting=True, + is_display=False, + ) + self._append( + AdjustablePvEnum, + self.pvname + ":TRIGGERSOURCE", + name="trigger_source", + is_setting=True, + is_display=False, + ) + # append_object_to_object(self,PvEnum,self.pvname+':TRIGGEREDGE',name='trigger_edge') + self._append( + AdjustableGetSet, + self._exposure_time.get_current_value, + lambda value: self._set_params((self._exposure_time, value)), + name="exposure_time", + is_setting=True, + is_display=True, + ) + self._append( + AdjustableGetSet, + self._gain.get_current_value, + lambda value: self._set_params((self._gain, value)), + name="gain", + is_setting=True, + is_display=True, + ) + + def set_roi(roi): + self._set_params( + [self._roixmin, roi[0]], + [self._roixmax, roi[1]], + [self._roiymin, roi[2]], + [self._roiymax, roi[3]], + ) + return (roi[0], roi[1], roi[2], roi[3]) + + self._append( + AdjustableVirtual, + [self._roixmin, self._roixmax, self._roiymin, self._roiymax], + lambda x_from, x_to, y_from, y_to: [x_from, x_to, y_from, y_to], + set_roi, + name="roi", + is_setting=True, + ) + + def _set_params(self, *args): + self.running(1) + for ob, val in args: + ob(val) + self._set_parameters(1) + self.running(2) + + def gui(self): + self._run_cmd( + f'caqtdm -macro "NAME={self.pvname},CAMNAME={self.pvname}" /sf/controls/config/qt/Camera/CameraExpert.ui' + ) + + +class QioptiqMicroscope(CameraBasler): + def __init__(self, pvname_camera, pvname_zoom=None, pvname_focus=None, name=None): + super().__init__(pvname_camera, name=name) + if pvname_zoom: + self._append(MotorRecord, pvname_zoom, name="zoom", is_setting=True) + if pvname_focus: + self._append(MotorRecord, pvname_focus, name="focus", is_setting=True) + + +class CameraPCO(Assembly): + def __init__(self, pvname, camserver_alias=None, name=None): + super().__init__(name=name) + self.pvname = pvname + if not camserver_alias: + camserver_alias = self.alias.get_full_name() + f"({pvname})" + self._append( + Pipeline, + self.pvname, + camserver_alias=camserver_alias, + name="config_cs", + ) + self.config_cs.set_alias() + self._append(AdjustablePvEnum, self.pvname + ":INIT", name="initialize") + self._append( + AdjustablePvEnum, + self.pvname + ":CAMERASTATUS", + name="camera_status", + is_display=True, + ) + self._append(AdjustablePv, self.pvname + ":BOARD", name="board_no") + self._append(AdjustablePv, self.pvname + ":SERIALNR", name="serial_no") + self._append(AdjustablePv, self.pvname + ":EXPOSURE", name="_exposure_time") + self._append(AdjustablePvEnum, self.pvname + ":ACQMODE", name="_acq_mode") + self._append(AdjustablePvEnum, self.pvname + ":RECMODE", name="_req_mode") + self._append(AdjustablePvEnum, self.pvname + ":STOREMODE", name="_store_mode") + self._append(AdjustablePv, self.pvname + ":HSSPEED", name="_hs_speed") + self._append( + AdjustablePvEnum, self.pvname + ":SCMOSREADOUT", name="_readout_mode" + ) + self._append(AdjustablePv, self.pvname + ":BINY", name="_binx") + self._append(AdjustablePv, self.pvname + ":BINY", name="_biny") + self._append(AdjustablePv, self.pvname + ":REGIONX_START", name="_roixmin") + self._append(AdjustablePv, self.pvname + ":REGIONX_END", name="_roixmax") + self._append(AdjustablePv, self.pvname + ":REGIONY_START", name="_roiymin") + self._append(AdjustablePv, self.pvname + ":REGIONY_END", name="_roiymax") + self._append( + AdjustablePvEnum, self.pvname + ":SET_PARAM", name="_set_parameters" + ) + self._append(AdjustablePvEnum, self.pvname + ":TRIGGER", name="trigger_on") + # append_object_to_object(self,PvEnum,self.pvname+':TRIGGEREDGE',name='trigger_edge') + + self._append( + AdjustableGetSet, + self._exposure_time.get_current_value, + lambda value: self._set_params((self._exposure_time, value)), + name="exposure_time", + is_setting=True, + ) + self._append( + AdjustableVirtual, + [self.camera_status], + lambda stat: stat == 2, + lambda running: 2 if running else 1, + name="running", + is_setting=True, + ) + + def set_roi(roi): + self._set_params( + [self._roixmin, roi[0]], + [self._roixmax, roi[1]], + [self._roiymin, roi[2]], + [self._roiymax, roi[3]], + ) + return (roi[0], roi[1], roi[2], roi[3]) + + self._append( + AdjustableVirtual, + [self._roixmin, self._roixmax, self._roiymin, self._roiymax], + lambda x_from, x_to, y_from, y_to: [x_from, x_to, y_from, y_to], + set_roi, + name="roi", + is_setting=True, + ) + + def _set_params(self, *args): + self.running(False) + for ob, val in args: + ob(val) + self._set_parameters(1) + self.running(True) + + def gui(self): + self._run_cmd( + f'caqtdm -macro "NAME={self.pvname},CAMNAME={self.pvname}" /sf/controls/config/qt/Camera/CameraExpert.ui' + ) diff --git a/eco/elements/adj_obj.py b/eco/elements/adj_obj.py index 3d86ea5..b7b1ec7 100644 --- a/eco/elements/adj_obj.py +++ b/eco/elements/adj_obj.py @@ -1,3 +1,4 @@ +from eco.elements.detector import DetectorGet from .assembly import Assembly from .adjustable import AdjustableGetSet @@ -5,10 +6,10 @@ from functools import partial class AdjustableObject(Assembly): - def __init__(self, adjustable_dict, name=None): + def __init__(self, adjustable_dict, is_setting_children = True, name=None): super().__init__(name=name) self._base_dict = adjustable_dict - self.init_object() + self.init_object(is_setting_children=is_setting_children) def set_field(self, fieldname, value): d = self._base_dict.get_current_value() @@ -29,7 +30,7 @@ class AdjustableObject(Assembly): self._base_dict.set_target_value(tmp) self.__init__(self._base_dict, name=self.name) - def init_object(self): + def init_object(self, is_setting_children=True): # super().__init__(name=self.name) for k, v in self._base_dict.get_current_value().items(): tadj = AdjustableGetSet( @@ -44,11 +45,51 @@ class AdjustableObject(Assembly): self._append( AdjustableObject(tadj, name=k), call_obj=False, + is_setting=is_setting_children, + name=ln, + is_display="recursive", + ) + else: + self._append( + tadj, call_obj=False, is_setting=is_setting_children, is_display=True, name=ln + ) + +class DetectorObject(Assembly): + def __init__(self, detector_dict, name=None): + super().__init__(name=name) + self._base_dict = detector_dict + self.init_object() + + + def get_field(self, fieldname): + d = self._base_dict.get_current_value() + if fieldname not in d.keys(): + raise Exception(f"{fieldname} is not in dictionary") + return d[fieldname] + + + def init_object(self): + # super().__init__(name=self.name) + for k, v in self._base_dict.get_current_value().items(): + tdet = DetectorGet( + partial(self.get_field, k), name=k + ) + if k in self.__dict__.keys(): + ln = f"{k}_" + else: + ln = f"{k}" + if type(v) is dict: + + self._append( + DetectorObject(tdet, name=k), + call_obj=False, is_setting=False, name=ln, is_display="recursive", ) else: self._append( - tadj, call_obj=False, is_setting=False, is_display=True, name=ln + tdet, call_obj=False, is_setting=False, is_display=True, name=ln ) + + diff --git a/eco/elements/adjustable.py b/eco/elements/adjustable.py index 2d4027e..91e59e3 100644 --- a/eco/elements/adjustable.py +++ b/eco/elements/adjustable.py @@ -548,7 +548,7 @@ class AdjustableVirtual: @tweak_option @value_property class AdjustableGetSet: - def __init__(self, foo_get, foo_set, precision=0, check_interval=None, name=None): + def __init__(self, foo_get, foo_set, precision=0, check_interval=None, cache_get_seconds=None, name=None): """assumes a waiting setterin function, in case no check_interval parameter is supplied""" self.alias = Alias(name) self.name = name @@ -556,6 +556,7 @@ class AdjustableGetSet: self._get = foo_get self._check_interval = check_interval self.precision = precision + self._cache_get_seconds = cache_get_seconds def set_and_wait(self, value): if self._check_interval: @@ -575,7 +576,18 @@ class AdjustableGetSet: ) def get_current_value(self): - return self._get() + ts = time.time() + if self._cache_get_seconds and hasattr(self,'_get_cache'): + if ts - self._get_cache[0] < self._cache_get_seconds: + value = self._get_cache[1] + else: + value = self._get() + else: + value = self._get() + if self._cache_get_seconds: + self._get_cache= (ts,value) + return value + @spec_convenience diff --git a/eco/elements/detector.py b/eco/elements/detector.py index 41d5ef2..f7a393b 100644 --- a/eco/elements/detector.py +++ b/eco/elements/detector.py @@ -1,6 +1,7 @@ from eco.elements.adjustable import AdjustableMemory from eco.elements.assembly import Assembly from eco.aliases import Alias +import time def value_property(Det, value_name="_value"): @@ -66,11 +67,23 @@ class DetectorVirtual(Assembly): @call_convenience @value_property class DetectorGet: - def __init__(self, foo_get, name=None): + def __init__(self, foo_get, cache_get_seconds=None, name=None): """ """ self.alias = Alias(name) self.name = name self._get = foo_get + self._cache_get_seconds = cache_get_seconds + def get_current_value(self): - return self._get() + ts = time.time() + if self._cache_get_seconds and hasattr(self,'_get_cache'): + if ts - self._get_cache[0] < self._cache_get_seconds: + value = self._get_cache[1] + else: + value = self._get() + else: + value = self._get() + if self._cache_get_seconds: + self._get_cache= (ts,value) + return value diff --git a/eco/endstations/bernina_sample_environments.py b/eco/endstations/bernina_sample_environments.py index 8f8482f..fd6aab6 100644 --- a/eco/endstations/bernina_sample_environments.py +++ b/eco/endstations/bernina_sample_environments.py @@ -35,9 +35,8 @@ def addSmarActRecordToSelf(self, Id=None, name=None, **kwargs): self.__dict__[name] = SmaractRecord(Id, name=name, **kwargs) self.alias.append(self.__dict__[name].alias) - class High_field_thz_chamber(Assembly): - def __init__(self, name=None, alias_namespace=None, configuration=[], illumination_mpod = None): + def __init__(self, name=None, alias_namespace=None, configuration=[], illumination_mpod = None, helium_control_valve=None): super().__init__(name=name) self.name = name self.alias = Alias(name) @@ -174,6 +173,26 @@ class High_field_thz_chamber(Assembly): if illumination_mpod: for illu in illumination_mpod: self._append(MpodChannel,illu['pvbase'], illu['channel_number'], module_string=illu['module_string'], name=illu['name']) + if helium_control_valve: + self._append(MpodChannel,helium_control_valve['pvbase'], helium_control_valve['channel_number'], module_string=helium_control_valve['module_string'], name="_helium_valve_mpod_ch", is_display=True, is_setting=True) + + def get_valve(voltage): + if voltage < 2.9: + val=0 + elif voltage > 5.5: + val=100 + else: + val = (voltage-2.9)/(5.5-2.9)*100 + return val + + def set_valve(val): + if val <1: + voltage = .5 + else: + voltage = val*(5.5-2.9)/100+2.9 + return voltage + + self._append(AdjustableVirtual, [self._helium_valve_mpod_ch.voltage], get_valve, set_valve, name=helium_control_valve["name"], is_display=True, is_setting=False) def moveout(self): change_in_pos = str( diff --git a/eco/timing/timing_diag.py b/eco/timing/timing_diag.py index a0b8669..32fdec1 100644 --- a/eco/timing/timing_diag.py +++ b/eco/timing/timing_diag.py @@ -1,4 +1,5 @@ from eco.detector.detectors_psi import DetectorBsStream +from eco.devices_general.pipelines_swissfel import Pipeline from ..elements.assembly import Assembly from ..devices_general.motors import SmaractStreamdevice, MotorRecord, SmaractRecord from ..elements.adjustable import AdjustableMemory, AdjustableVirtual @@ -44,6 +45,7 @@ class TimetoolBerninaUSD(Assembly): self.proc_client = PipelineClient() self.proc_pipeline = processing_pipeline + self._append(Pipeline,self.proc_pipeline, name='pipeline_projection', is_setting=True) self.proc_instance = processing_instance self.spectrometer_camera_channel = spectrometer_camera_channel self._append( diff --git a/eco/utilities/elog_scilog.py b/eco/utilities/elog_scilog.py new file mode 100755 index 0000000..fa30d30 --- /dev/null +++ b/eco/utilities/elog_scilog.py @@ -0,0 +1,102 @@ +from scilog import SciLog +from getpass import getuser as _getuser +from getpass import getpass as _getpass +import os, datetime, subprocess +import urllib3 +from pathlib import Path + +urllib3.disable_warnings() + + + + +def getDefaultElogInstance( + url='https://scilog.psi.ch/api/v1', + user="swissfelaramis-bernina@psi.ch", + pgroup = None, + **kwargs + ): + + + home = str(Path.home()) + if not user: + user=_getuser() + + if not ("password" in kwargs.keys()): + try: + with open(os.path.join(home, ".scilog_psi"), "r") as f: + _pw = f.read().strip() + except: + print("Enter scilog password for user: %s" % kwargs["user"]) + _pw = _getpass() + kwargs.update(dict(password=_pw)) + log = SciLog(url,options={"username": user, "password":kwargs['_pw']}) + if pgroup: + lbs = log.get_logbooks(ownerGroup=pgroup) + if len(lbs)> 1: + raise Exception(f'Found more than one elog for user group {pgroup}') + log.select_logbook(lbs[0]) + return log, user + + + +class Elog: + def __init__(self, url, screenshot_directory="", **kwargs): + self._log, self.user = getDefaultElogInstance(url, **kwargs) + self._screenshot = Screenshot(screenshot_directory) + # self.read = self._log.read + + def post(self, *args, Title=None, Author=None, Encoding="html", **kwargs): + """ """ + if Encoding == "html": + args = list(args) + args[0] = args[0].replace("\n", "
\n") + if not Author: + Author = self.user + return self._log.post( + *args, Title=Title, Author=Author, Encoding=Encoding, **kwargs + ) + + def screenshot(self, message="", window=False, desktop=False, delay=3, **kwargs): + filepath = self._screenshot.shoot()[0] + kwargs.update({"attachments": [filepath]}) + self.post(message, **kwargs) + + +class Screenshot: + def __init__(self, screenshot_directory="", **kwargs): + self._screenshot_directory = screenshot_directory + if not ("user" in kwargs.keys()): + self.user = _getuser() + else: + self.user = kwargs["user"] + + def show_directory(self): + + p = subprocess.Popen( + ["nautilus", self._screenshot_directory], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + + def shoot(self, message="", window=False, desktop=False, delay=3, **kwargs): + cmd = ["gnome-screenshot"] + if window: + cmd.append("-w") + cmd.append("--delay=%d" % delay) + elif desktop: + cmd.append("--delay=%d" % delay) + else: + cmd.append("-a") + tim = datetime.datetime.now() + fina = "%s-%s-%s_%s-%s-%s" % tim.timetuple()[:6] + if "Author" in kwargs.keys(): + fina += "_%s" % user + else: + fina += "_%s" % self.user + fina += ".png" + filepath = os.path.join(self._screenshot_directory, fina) + cmd.append("--file") + cmd.append(filepath) + p = subprocess.call(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + return filepath, p diff --git a/eco/utilities/swissfel_data_files.py b/eco/utilities/swissfel_data_files.py new file mode 100644 index 0000000..04ae9f4 --- /dev/null +++ b/eco/utilities/swissfel_data_files.py @@ -0,0 +1,12 @@ +from pathlib import Path + +class DataFiles: + def __init__(self,pgroup=None, data_path='/sf/bernina/data/'): + self.pgroup = pgroup + self.data_path = data_path + self.raw = Path(self.data_path) / Path(pgroup) / Path('raw') + + def get_available_runs(parse_numbers=True): + self.raw + + \ No newline at end of file diff --git a/eco/xdiagnostics/intensity_monitors.py b/eco/xdiagnostics/intensity_monitors.py index cb3a61e..62a8334 100755 --- a/eco/xdiagnostics/intensity_monitors.py +++ b/eco/xdiagnostics/intensity_monitors.py @@ -1,3 +1,4 @@ +from eco.devices_general.pipelines_swissfel import Pipeline from ..devices_general.motors import MotorRecord, SmaractRecord from ..devices_general.detectors import FeDigitizer from ..epics.detector import DetectorPvDataStream @@ -161,6 +162,7 @@ class SolidTargetDetectorPBPS(Assembly): fe_digi_channels={}, # calc=None, # calc_calib={}, + pipeline_computation=None, ): super().__init__(name=name) self.pvname = pvname @@ -304,6 +306,8 @@ class SolidTargetDetectorPBPS(Assembly): is_setting=True, is_display=False, ) + if pipeline_computation: + self._append(Pipeline, pipeline_computation,name='pipeline_comp', is_setting=True, is_display=False) def get_calibration_values(self, seconds=5, return_data=False): self.x_diodes.set_target_value(0).wait() From 9dcc32aaa71df9e17976d425f8422c20e0b292f5 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Wed, 30 Aug 2023 10:27:01 +0200 Subject: [PATCH 45/52] Changed config_cs, added set_cross method to basler cameras, added combined lxt delay stage to bernina, added FS adj limits to the PI hexapod axes, added optional check for limits in Virtual adjustables (kwarg check_limits, defaults to False), added time compensated motion with and without undulators to dcm --- eco/bernina/bernina.py | 38 ++- eco/devices_general/cameras_swissfel.py | 185 ++++++++++++- eco/devices_general/env_sensors.py | 18 +- eco/devices_general/pipelines_swissfel.py | 289 --------------------- eco/elements/adjustable.py | 18 +- eco/endstations/bernina_diffractometers.py | 97 ++++--- eco/endstations/hexapod.py | 52 +++- eco/loptics/bernina_laser.py | 56 ++++ eco/timing/timing_diag.py | 3 + eco/utilities/elog_scilog.py | 24 +- eco/utilities/recspace.py | 17 +- eco/xoptics/dcm_new.py | 36 ++- 12 files changed, 440 insertions(+), 393 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 98c3ff6..9b7cf55 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -86,6 +86,13 @@ namespace.append_obj( module_name="eco.fel.atmosphere", lazy=True, ) +namespace.append_obj( + "BerninaEnvironment", + name="env", + module_name="eco.devices_general.env_sensors", + lazy=True, +) + namespace.append_obj( "AdjustableFS", "/photonics/home/gac-bernina/eco/configuration/run_table_channels_CA", @@ -738,6 +745,7 @@ namespace.append_obj( diff_detector={"jf_id": "JF01T03V01"}, pgroup_adj=config_bernina.pgroup, invert_kappa_ellbow=config_bernina.invert_kappa_ellbow._value, + fina_hex_angle_offset="/sf/bernina/config/eco/reference_values/hex_pi_angle_offset.json", name="xrd", lazy=True, ) @@ -2063,15 +2071,6 @@ from ..microscopes import MicroscopeMotorRecord # ) -# delaystage_glob = MotorRecord( -# "SLAAR21-LMOT-M523:MOTOR_1", -# name="delaystage_glob", -# ) - -# delay_glob = DelayTime( -# delaystage_glob, -# name="delay_glob", -# ) namespace.append_obj( "SwissFel", @@ -2083,6 +2082,7 @@ namespace.append_obj( "DoubleCrystalMono", pvname="SAROP21-ODCM098", fel=fel, + las=las, undulator_deadband_eV=2.0, name="mono", lazy=True, @@ -2090,12 +2090,12 @@ namespace.append_obj( ) # namespace.append_obj( # "MonoTimecompensation", -# delay_glob, +# las.delay_glob, # mono.mono_und_energy, # "/sf/bernina/config/eco/reference_values/dcm_reference_timing.json", # "/sf/bernina/config/eco/reference_values/dcm_reference_invert_delay.json", # lazy=True, -# name="mono_time_corrected", +# name="mono_und_time_corrected", # module_name="eco.xoptics.dcm_pathlength_compensation", # ) @@ -2153,7 +2153,23 @@ namespace.append_obj( ############## experiment specific ############# +from eco.loptics.bernina_laser import Stage_LXT_Delay +class Laser_Xray_Timing(Assembly): + def __init__(self, name=None): + super().__init__(name=name) + self._append( + Stage_LXT_Delay, + las.delay_glob, + las.xlt, + direction=-1, + name="delay", + ) +namespace.append_obj( + Laser_Xray_Timing, + lazy=True, + name="lxt", +) ##combined delaystage with phase shifter motion## diff --git a/eco/devices_general/cameras_swissfel.py b/eco/devices_general/cameras_swissfel.py index 555141d..daf8c9e 100644 --- a/eco/devices_general/cameras_swissfel.py +++ b/eco/devices_general/cameras_swissfel.py @@ -1,14 +1,18 @@ from cam_server import CamClient, PipelineClient - +from matplotlib.backend_bases import MouseButton from eco.devices_general.utilities import Changer from ..aliases import Alias, append_object_to_object from ..elements.adjustable import AdjustableVirtual, AdjustableGetSet, value_property +from eco.elements.detector import DetectorGet from ..epics.adjustable import AdjustablePv, AdjustablePvEnum +from eco.elements.adj_obj import AdjustableObject, DetectorObject +from .pipelines_swissfel import Pipeline from ..elements.assembly import Assembly from .motors import MotorRecord import sys from pathlib import Path import time +import matplotlib.pyplot as plt sys.path.append("/sf/bernina/config/src/python/sf_databuffer/") import bufferutils @@ -30,6 +34,120 @@ def get_pipelineclient(): PIPELINE_CLIENT = PipelineClient() return PIPELINE_CLIENT +@value_property +class CamserverConfig2(Assembly): + def __init__(self, cam_id, camserver_alias=None, name=None, camserver_group=None): + super().__init__(name=name) + self.cam_id = cam_id + self.camserver_alias = camserver_alias + self.camserver_group = camserver_group + self._cross = None + self._append(AdjustableGetSet, + self._get_config, + self._set_config, + cache_get_seconds =.05, + precision=0, + check_interval=None, + name='_config', + is_setting=False, + is_display=False) + + self._append(AdjustableObject, self._config, name='config',is_setting=True, is_display='recursive') + self._append(DetectorGet, self._get_info, cache_get_seconds =.05, name='_info', is_setting=False, is_display=False) + self._append(DetectorObject, self._info, name='info', is_display='recursive', is_setting=False) + + @property + def pc(self): + return get_pipelineclient() + + @property + def cc(self): + return get_camclient() + + def _get_config(self): + return self.cc.get_camera_config(self.cam_id) + + def _set_config(self, value, hold=False): + return Changer( + target=value, + changer=lambda v: self.cc.set_camera_config(self.cam_id, v), + hold=hold, + ) + + def _get_info(self): + fields = { + "camera_geometry": self.cc.get_camera_geometry(self.cam_id), + "pipelines": self._get_pipelines(), + } + return fields + + ### convenience functions ### + def get_camera_image(self): + im = self.cc.get_camera_array(self.cam_id) + return im + + def set_alias(self, alias=None): + """creates an alias in the camera config on the server. If no alias is provided, it defaults to the camera name""" + if not alias: + alias = self.camserver_alias + self.set_config_fields({"alias": [alias.upper()]}) + + def set_group(self, group=None): + """adds the camera to the given group""" + if not group: + group = self.camserver_group + self.config.group(group) + + def _get_pipelines(self): + return [p for p in self.pc.get_pipelines() if self.cam_id in p] + + def set_config_fields(self, fields): + """fields is a dictionary containing the keys and values that should be updated, e.g. fields={'group': ['Laser', 'Bernina']}""" + config = self.cc.get_camera_config(self.cam_id) + config.update(fields) + self.cc.set_camera_config(self.cam_id, config) + + def set_config_fields_multiple_cams(self, conditions, fields): + """ + conditions is a dictionary holding the conditions to select a subset of cameras, e.g. {"group": Bernina} + fields is a dictionary containing the keys and values that should be updated, e.g. fields={'alias': ['huhu', 'duda']} + """ + cams = { + cam: self.cc.get_camera_config(cam) + for cam in self.cc.get_cameras() + if not "jungfrau" in cam + } + cams_selected = {} + for cam, cfg in cams.items(): + try: + if all([value in cfg[key] for key, value in conditions.items()]): + cfg.update(fields) + self.cc.set_camera_config(cam, cfg) + cams_selected[cam] = cfg + except Exception as e: + print(f"{type(e)} {e} in cam {cam}") + return cams_selected + + def clear_all_bernina_aliases(self, verbose=True): + cams_selected = self.set_config_fields_multiple_cams( + conditions={"group": "Bernina"}, fields={"alias": []} + ) + if verbose: + print(f"Reset alias of {len(cams_selected)} cameras") + print(cams_selected.keys()) + + def _run_cmd(self, line, silent=True): + if silent: + print(f"Starting following commandline silently:\n" + line) + with open(os.devnull, "w") as FNULL: + subprocess.Popen( + line, shell=True, stdout=FNULL, stderr=subprocess.STDOUT + ) + else: + subprocess.Popen(line, shell=True) + + def gui(self): + self._run_cmd(f'csm') @value_property class CamserverConfig(Assembly): @@ -50,7 +168,7 @@ class CamserverConfig(Assembly): def get_current_value(self): return self.cc.get_camera_config(self.cam_id) - def set_target_calue(self, value, hold=False): + def set_target_value(self, value, hold=False): return Changer( target=value, changer=lambda v: self.cc.set_camera_config(self.cam_id, v), @@ -165,13 +283,14 @@ class CameraBasler(Assembly): if not camserver_alias: camserver_alias = self.alias.get_full_name() + f" ({pvname})" self._append( - CamserverConfig, + CamserverConfig2, self.pvname, camserver_alias=camserver_alias, camserver_group=camserver_group, name="config_cs", is_display=False, ) + self.config_cs.set_alias() if camserver_group is not None: self.config_cs.set_group() @@ -344,6 +463,66 @@ class CameraBasler(Assembly): self._set_parameters(1) self.running(2) + def set_cross(self, x=None, y=None, x_um_per_px=None, y_um_per_px=None): + """set x and y position of the refetence marker on a camera px/um calibration is conserved if no new value is given""" + def prompt(x,y,x_um_per_px,y_um_per_px): + x=int(x) + y=int(y) + answer = input(f"Set the new cross position [{x}, {y}] with calibration [{x_um_per_px:.3}, {y_um_per_px:.3}] ([y]/n)?") or "y" + if answer == "y": + calib.reference_marker([x - 1, y - 1, x + 1, y + 1]) + calib.reference_marker_width(2 * x_um_per_px) + calib.reference_marker_height(2 * y_um_per_px) + print("\nNew calibration:") + print(calib) + else: + print("aborted") + + calib = self.config_cs.config.camera_calibration + print("Current calibration:") + print(calib) + try: + w = calib.reference_marker_width() + h = calib.reference_marker_height() + rm = calib.reference_marker() + if not x_um_per_px: + x_um_per_px = w / abs(rm[2] - rm[0]) + if not y_um_per_px: + y_um_per_px = h / abs(rm[3] - rm[1]) + except: + rm=[0,0,0,0] + x_um_per_px = 1 + y_um_per_px = 1 + if x is None or y is None: + x = (rm[2] + rm[0])/2 + y = (rm[3] + rm[1])/2 + img = self.config_cs.get_camera_image() + + run = True + def on_click(event): + if event.button is MouseButton.LEFT: + x = event.xdata + y = event.ydata + cross_plot.set_data(x,y) + plt.draw() + print(f'cross at x: {x:.4} and y: {y:.4}') + self.config_cs._cross = [x,y] + else: + plt.disconnect(bid) + plt.close(self.config_cs.cam_id) + + fig = plt.figure(num=self.config_cs.cam_id) + plt.title(f"Set cross: left mouse click, Finish: right click") + plt.imshow(img) + cross_plot = plt.plot(x,y, '+r', markersize=10)[0] + bid = fig.canvas.mpl_connect('button_press_event', on_click) + plt.show(block=True) + x, y = self.config_cs._cross + print(x,y) + prompt(x,y,x_um_per_px,y_um_per_px) + + + def gui(self): self._run_cmd( f'caqtdm -macro "NAME={self.pvname},CAMNAME={self.pvname}" /sf/controls/config/qt/Camera/CameraExpert.ui' diff --git a/eco/devices_general/env_sensors.py b/eco/devices_general/env_sensors.py index 87e67b4..7d0c65d 100644 --- a/eco/devices_general/env_sensors.py +++ b/eco/devices_general/env_sensors.py @@ -17,15 +17,15 @@ class I2cChannel(Assembly): name="description", is_setting=True, ) - self._append(DetectorPvData,f'{self.pvbase}_CH{self.channel_number}:TEMP', has_unit=True, name='temperature') - self._append(DetectorPvData,f'{self.pvbase}_CH{self.channel_number}:HUMIREL', has_unit=True, name = 'humidity') - self._append(DetectorPvData,f'{self.pvbase}_CH{self.channel_number}:PRES', has_unit=True, name='pressure') + self._append(DetectorPvData,f'{self.pvbase}_CH{self.channel_number}:TEMP', has_unit=True, name='temp') + self._append(DetectorPvData,f'{self.pvbase}_CH{self.channel_number}:HUMIREL', has_unit=True, name = 'humi') + self._append(DetectorPvData,f'{self.pvbase}_CH{self.channel_number}:PRES', has_unit=True, name='pres') self._append(AdjustablePv,f'{self.pvbase}_CH{self.channel_number}:ONOFF', name='enabled', is_setting=True) self._append(AdjustablePvEnum,f'{self.pvbase}_CH{self.channel_number}:SENSOR_TYPE', name='sensor_type', is_setting=True) self._pv_init = PV(self.pvbase+':INIT.PROC') def get_current_value(self,*args,**kwargs): - return f'{self.temperature.get_current_value(*args,**kwargs):.2f}°C , {self.humidity.get_current_value(*args,**kwargs):.2f}%relHum, {self.pressure.get_current_value(*args,**kwargs):.2f} mB' + return f'{self.temp.get_current_value(*args,**kwargs):.2f}°C , {self.humi.get_current_value(*args,**kwargs):.2f}%relHum, {self.pres.get_current_value(*args,**kwargs):.2f} mB' # def set_target_value(self,*args,**kwargs): # return self.enabled.set_target_value(*args,**kwargs) @@ -39,15 +39,15 @@ class I2cChannel(Assembly): class I2cModule(Assembly): def __init__(self,pvbase='SARES20-CI2C',N_channels=8, name=None): super().__init__(name=name) - for n in range(4,N_channels+1): + for n in range(1,N_channels+1): self._append(I2cChannel,pvbase,channelnumber=n,name=f'ch{n}') class BerninaEnvironment(Assembly): - def __init__(self,pvbases=['SLAAR21-LI2C01', 'SARES20-CI2C'],channels=[[1,2,3],[4,5,7,8]], name=None): + def __init__(self,pvbases=['SLAAR21-LI2C01', 'SARES20-CI2C'],channels=[[1,2,3,4,5,6,7,8],[4,5,6,7,8]], channelnames = [['las_tab1_in', 'las_tab1_cen', 'las_tab1_out', 'las_tab2_in', 'las_tab2_cen', 'las_tab2_out', 'las_tab2_below', 'tt_spec'], ['tt_opt', 'tt_kb', 'exp1', 'exp2', 'exp3']], name=None): super().__init__(name=name) - for pvbase,channelnumbers in zip(pvbases,channels): - for n in channelnumbers: - self._append(I2cChannel,pvbase,channelnumber=n,name=f'ch{n}') + for pvbase,channelnumbers,tnames in zip(pvbases,channels,channelnames): + for n,tname in zip(channelnumbers,tnames): + self._append(I2cChannel,pvbase,channelnumber=n,name=tname) diff --git a/eco/devices_general/pipelines_swissfel.py b/eco/devices_general/pipelines_swissfel.py index 29209e0..ce7bc8e 100644 --- a/eco/devices_general/pipelines_swissfel.py +++ b/eco/devices_general/pipelines_swissfel.py @@ -177,292 +177,3 @@ class Pipeline(Assembly): # s += f"{key:20} : {item}\n" # return s - -class CameraBasler(Assembly): - def __init__(self, pvname, camserver_alias=None, name=None, camserver_group=None): - super().__init__(name=name) - self.pvname = pvname - if not camserver_alias: - camserver_alias = self.alias.get_full_name() + f" ({pvname})" - self._append( - Pipeline, - self.pvname, - camserver_alias=camserver_alias, - camserver_group=camserver_group, - name="config_cs", - is_display=False, - ) - self.config_cs.set_alias() - if camserver_group is not None: - self.config_cs.set_group() - self._append( - AdjustablePvEnum, - self.pvname + ":INIT", - name="initialize", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePvEnum, - self.pvname + ":CAMERASTATUS", - name="running", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePv, - self.pvname + ":BOARD", - name="board_no", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePv, - self.pvname + ":SERIALNR", - name="serial_no", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePv, - self.pvname + ":EXPOSURE", - name="_exposure_time", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePvEnum, - self.pvname + ":ACQMODE", - name="_acq_mode", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePvEnum, - self.pvname + ":RECMODE", - name="_req_mode", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePvEnum, - self.pvname + ":STOREMODE", - name="_store_mode", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePv, - self.pvname + ":BINX", - name="_binx", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePv, - self.pvname + ":BINY", - name="_biny", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePv, - self.pvname + ":REGIONX_START", - name="_roixmin", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePv, - self.pvname + ":REGIONX_END", - name="_roixmax", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePv, - self.pvname + ":REGIONY_START", - name="_roiymin", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePv, - self.pvname + ":REGIONY_END", - name="_roiymax", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePvEnum, - self.pvname + ":SET_PARAM", - name="_set_parameters", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePvEnum, - self.pvname + ":TRIGGER", - name="trigger_on", - is_setting=True, - is_display=True, - ) - self._append( - AdjustablePv, - self.pvname + ":AMPGAIN", - name="_gain", - is_setting=True, - is_display=False, - ) - self._append( - AdjustablePvEnum, - self.pvname + ":TRIGGERSOURCE", - name="trigger_source", - is_setting=True, - is_display=False, - ) - # append_object_to_object(self,PvEnum,self.pvname+':TRIGGEREDGE',name='trigger_edge') - self._append( - AdjustableGetSet, - self._exposure_time.get_current_value, - lambda value: self._set_params((self._exposure_time, value)), - name="exposure_time", - is_setting=True, - is_display=True, - ) - self._append( - AdjustableGetSet, - self._gain.get_current_value, - lambda value: self._set_params((self._gain, value)), - name="gain", - is_setting=True, - is_display=True, - ) - - def set_roi(roi): - self._set_params( - [self._roixmin, roi[0]], - [self._roixmax, roi[1]], - [self._roiymin, roi[2]], - [self._roiymax, roi[3]], - ) - return (roi[0], roi[1], roi[2], roi[3]) - - self._append( - AdjustableVirtual, - [self._roixmin, self._roixmax, self._roiymin, self._roiymax], - lambda x_from, x_to, y_from, y_to: [x_from, x_to, y_from, y_to], - set_roi, - name="roi", - is_setting=True, - ) - - def _set_params(self, *args): - self.running(1) - for ob, val in args: - ob(val) - self._set_parameters(1) - self.running(2) - - def gui(self): - self._run_cmd( - f'caqtdm -macro "NAME={self.pvname},CAMNAME={self.pvname}" /sf/controls/config/qt/Camera/CameraExpert.ui' - ) - - -class QioptiqMicroscope(CameraBasler): - def __init__(self, pvname_camera, pvname_zoom=None, pvname_focus=None, name=None): - super().__init__(pvname_camera, name=name) - if pvname_zoom: - self._append(MotorRecord, pvname_zoom, name="zoom", is_setting=True) - if pvname_focus: - self._append(MotorRecord, pvname_focus, name="focus", is_setting=True) - - -class CameraPCO(Assembly): - def __init__(self, pvname, camserver_alias=None, name=None): - super().__init__(name=name) - self.pvname = pvname - if not camserver_alias: - camserver_alias = self.alias.get_full_name() + f"({pvname})" - self._append( - Pipeline, - self.pvname, - camserver_alias=camserver_alias, - name="config_cs", - ) - self.config_cs.set_alias() - self._append(AdjustablePvEnum, self.pvname + ":INIT", name="initialize") - self._append( - AdjustablePvEnum, - self.pvname + ":CAMERASTATUS", - name="camera_status", - is_display=True, - ) - self._append(AdjustablePv, self.pvname + ":BOARD", name="board_no") - self._append(AdjustablePv, self.pvname + ":SERIALNR", name="serial_no") - self._append(AdjustablePv, self.pvname + ":EXPOSURE", name="_exposure_time") - self._append(AdjustablePvEnum, self.pvname + ":ACQMODE", name="_acq_mode") - self._append(AdjustablePvEnum, self.pvname + ":RECMODE", name="_req_mode") - self._append(AdjustablePvEnum, self.pvname + ":STOREMODE", name="_store_mode") - self._append(AdjustablePv, self.pvname + ":HSSPEED", name="_hs_speed") - self._append( - AdjustablePvEnum, self.pvname + ":SCMOSREADOUT", name="_readout_mode" - ) - self._append(AdjustablePv, self.pvname + ":BINY", name="_binx") - self._append(AdjustablePv, self.pvname + ":BINY", name="_biny") - self._append(AdjustablePv, self.pvname + ":REGIONX_START", name="_roixmin") - self._append(AdjustablePv, self.pvname + ":REGIONX_END", name="_roixmax") - self._append(AdjustablePv, self.pvname + ":REGIONY_START", name="_roiymin") - self._append(AdjustablePv, self.pvname + ":REGIONY_END", name="_roiymax") - self._append( - AdjustablePvEnum, self.pvname + ":SET_PARAM", name="_set_parameters" - ) - self._append(AdjustablePvEnum, self.pvname + ":TRIGGER", name="trigger_on") - # append_object_to_object(self,PvEnum,self.pvname+':TRIGGEREDGE',name='trigger_edge') - - self._append( - AdjustableGetSet, - self._exposure_time.get_current_value, - lambda value: self._set_params((self._exposure_time, value)), - name="exposure_time", - is_setting=True, - ) - self._append( - AdjustableVirtual, - [self.camera_status], - lambda stat: stat == 2, - lambda running: 2 if running else 1, - name="running", - is_setting=True, - ) - - def set_roi(roi): - self._set_params( - [self._roixmin, roi[0]], - [self._roixmax, roi[1]], - [self._roiymin, roi[2]], - [self._roiymax, roi[3]], - ) - return (roi[0], roi[1], roi[2], roi[3]) - - self._append( - AdjustableVirtual, - [self._roixmin, self._roixmax, self._roiymin, self._roiymax], - lambda x_from, x_to, y_from, y_to: [x_from, x_to, y_from, y_to], - set_roi, - name="roi", - is_setting=True, - ) - - def _set_params(self, *args): - self.running(False) - for ob, val in args: - ob(val) - self._set_parameters(1) - self.running(True) - - def gui(self): - self._run_cmd( - f'caqtdm -macro "NAME={self.pvname},CAMNAME={self.pvname}" /sf/controls/config/qt/Camera/CameraExpert.ui' - ) diff --git a/eco/elements/adjustable.py b/eco/elements/adjustable.py index 91e59e3..b8bade4 100644 --- a/eco/elements/adjustable.py +++ b/eco/elements/adjustable.py @@ -304,12 +304,12 @@ def value_property(Adj, wait_for_change=True, value_name="_value"): @tweak_option @value_property class DummyAdjustable: - def __init__(self, name="no_adjustable"): + def __init__(self, name="no_adjustable", limits=[-100,100]): self.name = name self.alias = Alias(name) self.current_value = 0 - self.limits = [-100,100] + self.limits = tuple(limits) def get_current_value(self): return self.current_value @@ -320,10 +320,12 @@ class DummyAdjustable: return Changer( target=value, parent=self, changer=changer, hold=hold, stopper=None ) + def get_limits(self): return self.limits - def set_limits(self, limits): - self.limits = limits + + def set_limits(self, lowlim,highlim): + self.limits = (lowlim,highlim) def __repr__(self): name = self.name @@ -467,6 +469,7 @@ class AdjustableVirtual: append_aliases=False, name=None, unit=None, + check_limits=False, ): self.name = name self.alias = Alias(name) @@ -482,6 +485,7 @@ class AdjustableVirtual: self._foo_get_current_value = foo_get_current_value self._reset_current_value_to = reset_current_value_to self._change_simultaneously = change_simultaneously + self._check_limits = check_limits if reset_current_value_to: for adj in self._adjustables: if not hasattr(adj, "reset_current_value_to"): @@ -495,6 +499,12 @@ class AdjustableVirtual: vals = (vals,) def changer(value): + if self._check_limits: + if not self.check_target_value_within_limits(value): + raise Exception( + f"Target value of virtual adjustable {self.name} is higher than limit values of {[adj.name for adj in self._adjustables]}!" + ) + if self._change_simultaneously: self._active_changers = [ adj.set_target_value(val, hold=False) diff --git a/eco/endstations/bernina_diffractometers.py b/eco/endstations/bernina_diffractometers.py index bdc7ba2..de92083 100644 --- a/eco/endstations/bernina_diffractometers.py +++ b/eco/endstations/bernina_diffractometers.py @@ -415,6 +415,7 @@ class XRDYou(Assembly): diff_detector=None, invert_kappa_ellbow=True, pgroup_adj=None, + fina_hex_angle_offset=None, diffcalc=True, ): """X-ray diffractometer platform in AiwssFEL Bernina.\ @@ -607,49 +608,63 @@ class XRDYou(Assembly): ) if "phi_hex" in self.configuration: + ### motors PI hexapod ### - append_object_to_object( - self, - AdjustablePv, - "SARES20-HEX_PI:SET-POSI-X", - pvreadbackname="SARES20-HEX_PI:POSI-X", - name="xhex", - ) - append_object_to_object( - self, - AdjustablePv, - "SARES20-HEX_PI:SET-POSI-Y", - pvreadbackname="SARES20-HEX_PI:POSI-Y", - name="yhex", - ) - append_object_to_object( - self, - AdjustablePv, - "SARES20-HEX_PI:SET-POSI-Z", - pvreadbackname="SARES20-HEX_PI:POSI-Z", - name="zhex", - ) - append_object_to_object( - self, - AdjustablePv, - "SARES20-HEX_PI:SET-POSI-U", - pvreadbackname="SARES20-HEX_PI:POSI-U", - name="uhex", - ) - append_object_to_object( - self, - AdjustablePv, - "SARES20-HEX_PI:SET-POSI-V", - pvreadbackname="SARES20-HEX_PI:POSI-V", - name="vhex", - ) - append_object_to_object( - self, - AdjustablePv, - "SARES20-HEX_PI:SET-POSI-W", - pvreadbackname="SARES20-HEX_PI:POSI-W", - name="whex", + if fina_hex_angle_offset: + fina_hex_angle_offset = Path(fina_hex_angle_offset).expanduser() + + self._append( + HexapodPI, + "SARES20-HEX_PI", + name="hex", + fina_angle_offset=fina_hex_angle_offset, + is_setting=True, + is_display="recursive", ) +# if "phi_hex" in self.configuration: +# ### motors PI hexapod ### +# append_object_to_object( +# self, +# AdjustablePv, +# "SARES20-HEX_PI:SET-POSI-X", +# pvreadbackname="SARES20-HEX_PI:POSI-X", +# name="xhex", +# ) +# append_object_to_object( +# self, +# AdjustablePv, +# "SARES20-HEX_PI:SET-POSI-Y", +# pvreadbackname="SARES20-HEX_PI:POSI-Y", +# name="yhex", +# ) +# append_object_to_object( +# self, +# AdjustablePv, +# "SARES20-HEX_PI:SET-POSI-Z", +# pvreadbackname="SARES20-HEX_PI:POSI-Z", +# name="zhex", +# ) +# append_object_to_object( +# self, +# AdjustablePv, +# "SARES20-HEX_PI:SET-POSI-U", +# pvreadbackname="SARES20-HEX_PI:POSI-U", +# name="uhex", +# ) +# append_object_to_object( +# self, +# AdjustablePv, +# "SARES20-HEX_PI:SET-POSI-V", +# pvreadbackname="SARES20-HEX_PI:POSI-V", +# name="vhex", +# ) +# append_object_to_object( +# self, +# AdjustablePv, +# "SARES20-HEX_PI:SET-POSI-W", +# pvreadbackname="SARES20-HEX_PI:POSI-W", +# name="whex", +# ) if "kappa" in self.configuration: self._append( diff --git a/eco/endstations/hexapod.py b/eco/endstations/hexapod.py index 15dbf26..abe59a5 100644 --- a/eco/endstations/hexapod.py +++ b/eco/endstations/hexapod.py @@ -1,3 +1,4 @@ +import time from epics import PV from ..elements.adjustable import AdjustableFS, AdjustableVirtual from ..epics.adjustable import AdjustablePv, AdjustablePvEnum @@ -25,13 +26,43 @@ class Hexapod_PI: for i in "RST" ] +class AdjustablePiHex(AdjustablePv): + def __init__(self, pvname=None, pvreadbackname=None, accuracy=None, name=None): + super().__init__(pvname, pvreadbackname=pvreadbackname, accuracy=accuracy, name=name) + self.limit_high = AdjustableFS(f'/sf/bernina/config/eco/reference_values/hex_pi_{name}_limit_high.json', default_value=0) + self.limit_low = AdjustableFS(f'/sf/bernina/config/eco/reference_values/hex_pi_{name}_limit_low.json', default_value=0) + + + def change(self, value): + if self.limit_low: + if value < self.limit_low(): + raise Exception( + f"Target value of {self.name} is smaller than limit value!" + ) + if self.limit_high: + if self.limit_high() < value: + raise Exception( + f"Target value of {self.name} is higher than limit value!" + ) + self._pv.put(value) + time.sleep(0.1) + while self.get_change_done() == 0: + time.sleep(0.1) + + def get_limits(self): + return (self.limit_low(), self.limit_high()) + + def set_limits(self, limit_low, limit_high): + self.limit_low(limit_low) + self.limit_high(limit_high) + class HexapodPI(Assembly): def __init__(self, pvname, name=None, fina_angle_offset=None): super().__init__(name=name) self.pvname = pvname self._append( - AdjustablePv, + AdjustablePiHex, self.pvname + ":SET-POSI-X", pvreadbackname=self.pvname + ":POSI-X", accuracy=0.001, @@ -39,7 +70,7 @@ class HexapodPI(Assembly): is_setting=True, ) self._append( - AdjustablePv, + AdjustablePiHex, self.pvname + ":SET-POSI-Y", pvreadbackname=self.pvname + ":POSI-Y", accuracy=0.001, @@ -47,7 +78,7 @@ class HexapodPI(Assembly): is_setting=True, ) self._append( - AdjustablePv, + AdjustablePiHex, self.pvname + ":SET-POSI-Z", pvreadbackname=self.pvname + ":POSI-Z", accuracy=0.001, @@ -55,7 +86,7 @@ class HexapodPI(Assembly): is_setting=True, ) self._append( - AdjustablePv, + AdjustablePiHex, self.pvname + ":SET-POSI-U", pvreadbackname=self.pvname + ":POSI-U", accuracy=0.001, @@ -63,7 +94,7 @@ class HexapodPI(Assembly): is_setting=True, ) self._append( - AdjustablePv, + AdjustablePiHex, self.pvname + ":SET-POSI-V", pvreadbackname=self.pvname + ":POSI-V", accuracy=0.001, @@ -71,7 +102,7 @@ class HexapodPI(Assembly): is_setting=True, ) self._append( - AdjustablePv, + AdjustablePiHex, self.pvname + ":SET-POSI-W", pvreadbackname=self.pvname + ":POSI-W", accuracy=0.001, @@ -79,7 +110,7 @@ class HexapodPI(Assembly): is_setting=True, ) self._append( - AdjustablePv, + AdjustablePiHex, self.pvname + ":SET-PIVOT-R", pvreadbackname=self.pvname + ":PIVOT-R", accuracy=0.001, @@ -87,7 +118,7 @@ class HexapodPI(Assembly): is_setting=True, ) self._append( - AdjustablePv, + AdjustablePiHex, self.pvname + ":SET-PIVOT-S", pvreadbackname=self.pvname + ":PIVOT-S", accuracy=0.001, @@ -95,7 +126,7 @@ class HexapodPI(Assembly): is_setting=True, ) self._append( - AdjustablePv, + AdjustablePiHex, self.pvname + ":SET-PIVOT-T", pvreadbackname=self.pvname + ":PIVOT-T", accuracy=0.001, @@ -116,6 +147,7 @@ class HexapodPI(Assembly): reset_current_value_to=False, append_aliases=False, change_simultaneously=False, + check_limits=True, name="x", is_setting=False, ) @@ -128,6 +160,7 @@ class HexapodPI(Assembly): ), reset_current_value_to=False, change_simultaneously=False, + check_limits=True, append_aliases=False, name="y", is_setting=False, @@ -142,6 +175,7 @@ class HexapodPI(Assembly): reset_current_value_to=False, append_aliases=False, change_simultaneously=False, + check_limits=True, name="z", is_setting=False, ) diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index e8a7616..7e560a6 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -157,6 +157,55 @@ class FilterWheelAttenuator(Assembly): self.wheel_1.home() self.wheel_2.home() +class Stage_LXT_Delay(AdjustableVirtual): + def __init__(self, fine_delay_adj, coarse_delay_adj, direction=1, name=None): + self._fine_delay_adj = fine_delay_adj + self._coarse_delay_adj = coarse_delay_adj + self._direction=direction + self.switch_threshold = AdjustableFS( + f"/photonics/home/gac-bernina/eco/configuration/{name}_combined_delay_phase_shifter_threshold", + name="switch_threshold", + default_value=50e-12, + ) + self.offset_fine_adj = AdjustableFS( + f"/photonics/home/gac-bernina/eco/configuration/{name}_conbined_fine_adj_offset", + name="offset_fine_adj", + default_value=0., + ) + self.offset_coarse_adj = AdjustableFS( + f"/photonics/home/gac-bernina/eco/configuration/{name}_combined_coarse_adj_offset", + name="offset_coarse_adj", + default_value=0., + ) + + + AdjustableVirtual.__init__( + self, + [self._fine_delay_adj, self._coarse_delay_adj], + self._get_comb_delay, + self._set_comb_delay, + name=name, + unit="s", + ) + + def _get_comb_delay(self, pd, ps): + ps_rel = ps - self.offset_coarse_adj() + pd_rel = pd - self.offset_fine_adj() + return (ps_rel + pd_rel)*self._direction + + def _set_comb_delay(self, delay): + if delay < abs(self.switch_threshold()): + ### check to prevent slow phaseshifter corrections <50fs + if np.abs(self._coarse_delay_adj() - self.offset_coarse_adj()) > 50e-15: + ps_pos = self.offset_coarse_adj() + else: + ps_pos = None + pd_pos = self.offset_fine_adj() + delay + else: + ps_pos = self.offset_coarse_adj() + delay + pd_pos = self.offset_fine_adj() + return self._direction*pd_pos, self._direction*ps_pos + class LaserBernina(Assembly): def __init__(self, pvname, name=None): @@ -258,6 +307,13 @@ class LaserBernina(Assembly): is_setting=True, ) # self._append( + # Stage_LXT_Delay, + # self.delay_glob, + # self.xlt, + # direction=1, + # name="delay", + # ) + # self._append( # SmaractStreamdevice, # pvname="SARES23-ESB18", # name="delaystage_thz", diff --git a/eco/timing/timing_diag.py b/eco/timing/timing_diag.py index 32fdec1..975f949 100644 --- a/eco/timing/timing_diag.py +++ b/eco/timing/timing_diag.py @@ -24,6 +24,7 @@ class TimetoolBerninaUSD(Assembly): self, name=None, processing_pipeline="SARES20-CAMS142-M5_psen_db", + edge_finding_pipeline="SAROP21-ATT01_proc", processing_instance="SARES20-CAMS142-M5_psen_db", spectrometer_camera_channel="SARES20-CAMS142-M5:FPICTURE", spectrometer_pvname="SARES20-CAMS142-M5", @@ -47,6 +48,8 @@ class TimetoolBerninaUSD(Assembly): self.proc_pipeline = processing_pipeline self._append(Pipeline,self.proc_pipeline, name='pipeline_projection', is_setting=True) self.proc_instance = processing_instance + self.proc_pipeline_edge = edge_finding_pipeline + self._append(Pipeline,self.proc_pipeline_edge, name='pipeline_edgefinding', is_setting=True) self.spectrometer_camera_channel = spectrometer_camera_channel self._append( Target_xyz, diff --git a/eco/utilities/elog_scilog.py b/eco/utilities/elog_scilog.py index fa30d30..497d1ec 100755 --- a/eco/utilities/elog_scilog.py +++ b/eco/utilities/elog_scilog.py @@ -8,19 +8,15 @@ from pathlib import Path urllib3.disable_warnings() - - def getDefaultElogInstance( - url='https://scilog.psi.ch/api/v1', - user="swissfelaramis-bernina@psi.ch", - pgroup = None, - **kwargs - ): - - + url="https://scilog.psi.ch/api/v1", + user="swissfelaramis-bernina@psi.ch", + pgroup=None, + **kwargs, +): home = str(Path.home()) if not user: - user=_getuser() + user = _getuser() if not ("password" in kwargs.keys()): try: @@ -30,16 +26,15 @@ def getDefaultElogInstance( print("Enter scilog password for user: %s" % kwargs["user"]) _pw = _getpass() kwargs.update(dict(password=_pw)) - log = SciLog(url,options={"username": user, "password":kwargs['_pw']}) + log = SciLog(url, options={"username": user, "password": kwargs["password"]}) if pgroup: lbs = log.get_logbooks(ownerGroup=pgroup) - if len(lbs)> 1: - raise Exception(f'Found more than one elog for user group {pgroup}') + if len(lbs) > 1: + raise Exception(f"Found more than one elog for user group {pgroup}") log.select_logbook(lbs[0]) return log, user - class Elog: def __init__(self, url, screenshot_directory="", **kwargs): self._log, self.user = getDefaultElogInstance(url, **kwargs) @@ -72,7 +67,6 @@ class Screenshot: self.user = kwargs["user"] def show_directory(self): - p = subprocess.Popen( ["nautilus", self._screenshot_directory], stdout=subprocess.PIPE, diff --git a/eco/utilities/recspace.py b/eco/utilities/recspace.py index 858ca63..a0e3bf0 100644 --- a/eco/utilities/recspace.py +++ b/eco/utilities/recspace.py @@ -21,7 +21,7 @@ class Diffractometer_Dummy(Assembly): self.configuration = ["base", "arm"] adjs = ["nu", "mu", "delta", "eta", "chi", "phi"] for adj in adjs: - self._append(DummyAdjustable, name=adj, is_setting=True, is_display=True) + self._append(DummyAdjustable, name=adj, is_setting=True, is_display=True, limits=[-180,180]) diffractometer_dummy = Diffractometer_Dummy(name = "dummy") @@ -332,7 +332,7 @@ class DiffGeometryYou(Assembly): kwargs["eta"], kwargs["chi"], kwargs["phi"] ) kwargs.update({"eta_kap": eta_kap, "kappa": kappa, "phi_kap": phi_kap}) - return [kwargs[key] for key in self._diff_adjs.keys()] + return {key:kwargs[key] for key in self._diff_adjs.keys()} def convert_to_you( self, @@ -360,16 +360,21 @@ class DiffGeometryYou(Assembly): def _calc_angles_unique_diffractometer(self, hkl): angles = self.calc_angles_unique(*hkl) - return self.convert_from_you(**angles) + angles_diff_dict = self.convert_from_you(**angles) + return [angles_diff_dict[tk] for tk in self._diff_adjs.keys()] def check_target_value_within_limits(self, **kwargs): ### virtual adjustables got a new function check_target_value_within_limits(values) in_lims = [] - target_values = self.convert_from_you(**kwargs) - for val, adj in zip(target_values, self._diff_adjs.values()): + target_dict = self.convert_from_you(**kwargs) + for axname, target_value in target_dict.items(): + adj = self._diff_adjs[axname] + + # for val, adj in zip(target_dict, self._diff_adjs.values()): if hasattr(adj, "get_limits"): lim_low, lim_high = adj.get_limits() - in_lims.append((lim_low < val) and (val < lim_high)) + in_lims.append((lim_low < target_value) and (target_value < lim_high)) + # print(axname,lim_low,target_value,lim_high) else: raise Exception(f"Failed to get limits of adjustable {adj.name}") return all(in_lims) diff --git a/eco/xoptics/dcm_new.py b/eco/xoptics/dcm_new.py index d33a5b8..f6f76b4 100644 --- a/eco/xoptics/dcm_new.py +++ b/eco/xoptics/dcm_new.py @@ -15,7 +15,7 @@ from ..elements.adjustable import ( ) from ..devices_general.utilities import Changer from ..elements.assembly import Assembly - +from eco.xoptics.dcm_pathlength_compensation import MonoTimecompensation @spec_convenience @update_changes @@ -28,10 +28,12 @@ class DoubleCrystalMono(Assembly): energy_sp="SAROP21-ARAMIS:ENERGY_SP", energy_rb="SAROP21-ARAMIS:ENERGY", fel=None, + las = None, undulator_deadband_eV=None, ): super().__init__(name=name) - self.fel = fel + self._fel = fel + self._las = las self.undulator_deadband_eV = undulator_deadband_eV self.pvname = pvname self._append( @@ -91,7 +93,7 @@ class DoubleCrystalMono(Assembly): is_display=False, ) self.settings_collection.append(self) - if self.fel is not None: + if self._fel is not None: self._append( AdjustableFS, "/photonics/home/gac-bernina/eco/configuration/mono_und_offset", @@ -104,7 +106,7 @@ class DoubleCrystalMono(Assembly): ofs = np.array(self.mono_und_calib()).T fel_ofs = ofs[1][np.argmin(abs(ofs[0] - en))] e_und_curr = ( - self.fel.aramis_photon_energy_undulators.get_current_value() + self._fel.aramis_photon_energy_undulators.get_current_value() ) if ( @@ -120,17 +122,39 @@ class DoubleCrystalMono(Assembly): self._append( AdjustableVirtual, - [self.energy, self.fel.aramis_photon_energy_undulators], + [self.energy, self._fel.aramis_photon_energy_undulators], en_get, en_set, name="mono_und_energy", ) + if self._las is not None: + self._append( + MonoTimecompensation, + self._las.delay_glob, + self.mono_und_energy, + "/sf/bernina/config/eco/reference_values/dcm_reference_timing.json", + "/sf/bernina/config/eco/reference_values/dcm_reference_invert_delay.json", + name="mono_und_energy_time_corrected", + is_setting=False, + is_display=True, + ) + if self._las is not None: + self._append( + MonoTimecompensation, + self._las.delay_glob, + self.energy, + "/sf/bernina/config/eco/reference_values/dcm_reference_timing.json", + "/sf/bernina/config/eco/reference_values/dcm_reference_invert_delay.json", + name="mono_time_corrected", + is_setting=False, + is_display=True, + ) def add_mono_und_calibration_point(self): mono_energy = self.energy.get_current_value() fel_offset = ( self.energy.get_current_value() / 1000 - - self.fel.aramis_photon_energy_undulators.get_current_value() + - self._fel.aramis_photon_energy_undulators.get_current_value() ) self.mono_und_calib.mvr([[mono_energy, fel_offset]]) From 3af72a61f2fed21b0fbc80da829539b0382e0955 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Wed, 30 Aug 2023 11:27:08 +0200 Subject: [PATCH 46/52] added units to the PI hexpoad stages --- eco/endstations/bernina_diffractometers.py | 4 ++-- eco/endstations/hexapod.py | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/eco/endstations/bernina_diffractometers.py b/eco/endstations/bernina_diffractometers.py index de92083..f09490f 100644 --- a/eco/endstations/bernina_diffractometers.py +++ b/eco/endstations/bernina_diffractometers.py @@ -595,14 +595,14 @@ class XRDYou(Assembly): self._append( MotorRecord_new, Id + ":MOT_HEX_TX", - name="tphi", + name="transl_eta", is_setting=True, is_display=True, ) self._append( MotorRecord_new, Id + ":MOT_HEX_RX", - name="phi", + name="eta", is_setting=True, is_display=True, ) diff --git a/eco/endstations/hexapod.py b/eco/endstations/hexapod.py index abe59a5..3fe2234 100644 --- a/eco/endstations/hexapod.py +++ b/eco/endstations/hexapod.py @@ -27,8 +27,8 @@ class Hexapod_PI: ] class AdjustablePiHex(AdjustablePv): - def __init__(self, pvname=None, pvreadbackname=None, accuracy=None, name=None): - super().__init__(pvname, pvreadbackname=pvreadbackname, accuracy=accuracy, name=name) + def __init__(self, pvname=None, pvreadbackname=None, accuracy=None, unit=None, name=None): + super().__init__(pvname, pvreadbackname=pvreadbackname, accuracy=accuracy, unit=unit, name=name) self.limit_high = AdjustableFS(f'/sf/bernina/config/eco/reference_values/hex_pi_{name}_limit_high.json', default_value=0) self.limit_low = AdjustableFS(f'/sf/bernina/config/eco/reference_values/hex_pi_{name}_limit_low.json', default_value=0) @@ -66,6 +66,7 @@ class HexapodPI(Assembly): self.pvname + ":SET-POSI-X", pvreadbackname=self.pvname + ":POSI-X", accuracy=0.001, + unit="mm", name="x_raw", is_setting=True, ) @@ -74,6 +75,7 @@ class HexapodPI(Assembly): self.pvname + ":SET-POSI-Y", pvreadbackname=self.pvname + ":POSI-Y", accuracy=0.001, + unit="mm", name="y_raw", is_setting=True, ) @@ -82,6 +84,7 @@ class HexapodPI(Assembly): self.pvname + ":SET-POSI-Z", pvreadbackname=self.pvname + ":POSI-Z", accuracy=0.001, + unit="mm", name="z_raw", is_setting=True, ) @@ -90,6 +93,7 @@ class HexapodPI(Assembly): self.pvname + ":SET-POSI-U", pvreadbackname=self.pvname + ":POSI-U", accuracy=0.001, + unit="deg", name="rx_raw", is_setting=True, ) @@ -98,6 +102,7 @@ class HexapodPI(Assembly): self.pvname + ":SET-POSI-V", pvreadbackname=self.pvname + ":POSI-V", accuracy=0.001, + unit="deg", name="ry_raw", is_setting=True, ) @@ -106,6 +111,7 @@ class HexapodPI(Assembly): self.pvname + ":SET-POSI-W", pvreadbackname=self.pvname + ":POSI-W", accuracy=0.001, + unit="deg", name="rz_raw", is_setting=True, ) @@ -114,6 +120,7 @@ class HexapodPI(Assembly): self.pvname + ":SET-PIVOT-R", pvreadbackname=self.pvname + ":PIVOT-R", accuracy=0.001, + unit="mm", name="pivot_x", is_setting=True, ) @@ -122,6 +129,7 @@ class HexapodPI(Assembly): self.pvname + ":SET-PIVOT-S", pvreadbackname=self.pvname + ":PIVOT-S", accuracy=0.001, + unit="mm", name="pivot_y", is_setting=True, ) @@ -130,6 +138,7 @@ class HexapodPI(Assembly): self.pvname + ":SET-PIVOT-T", pvreadbackname=self.pvname + ":PIVOT-T", accuracy=0.001, + unit="mm", name="pivot_z", is_setting=True, ) @@ -148,6 +157,7 @@ class HexapodPI(Assembly): append_aliases=False, change_simultaneously=False, check_limits=True, + unit="mm", name="x", is_setting=False, ) @@ -162,6 +172,7 @@ class HexapodPI(Assembly): change_simultaneously=False, check_limits=True, append_aliases=False, + unit="mm", name="y", is_setting=False, ) @@ -176,6 +187,7 @@ class HexapodPI(Assembly): append_aliases=False, change_simultaneously=False, check_limits=True, + unit="mm", name="z", is_setting=False, ) From 06980fa5b9e4daa42ab67cad233a067584e57c8f Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Thu, 7 Sep 2023 16:57:34 +0200 Subject: [PATCH 47/52] fixes devs for Ovuka --- eco/bernina/bernina.py | 655 +++++++++++++-------- eco/detector/jungfrau.py | 92 +++ eco/devices_general/env_sensors.py | 16 +- eco/elements/memory.py | 30 +- eco/endstations/bernina_diffractometers.py | 119 ++-- eco/endstations/bernina_robot.py | 22 +- eco/epics/adjustable.py | 109 +++- eco/fel/swissfel.py | 3 +- eco/utilities/elog_scilog.py | 47 +- eco/xdiagnostics/profile_monitors.py | 11 +- eco/xoptics/dcm_new.py | 2 +- 11 files changed, 761 insertions(+), 345 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 9b7cf55..b95b9b0 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -22,6 +22,7 @@ import pyttsx3 from ..utilities.path_alias import PathAlias import sys, os +import numpy as np from IPython import get_ipython @@ -362,7 +363,7 @@ namespace.append_obj( # }, name="mon_opt_new", module_name="eco.xdiagnostics.intensity_monitors", - pipeline_computation='SAROP21-PBPS133_proc', + pipeline_computation="SAROP21-PBPS133_proc", lazy=True, ) @@ -423,6 +424,11 @@ namespace.append_obj( "Pprm", "SAROP21-PPRM138", "SAROP21-PPRM138", + bs_channels={ + "intensity": "SAROP21-PPRM138:intensity", + "xpos": "SAROP21-PPRM138:x_fit_mean", + "ypos": "SAROP21-PPRM138:y_fit_mean", + }, module_name="eco.xdiagnostics.profile_monitors", name="prof_att", in_target=3, @@ -682,7 +688,7 @@ namespace.append_obj( name="slit_att", lazy=True, module_name="eco.xoptics.slits", -), +) namespace.append_obj( "WagoAnalogInputs", "SARES20-CWAG-GPS01", @@ -706,7 +712,6 @@ namespace.append_obj( module_name="eco.devices_general.wago", ) - namespace.append_obj( "GudeStrip", "SARES20-CPPS-01", @@ -728,6 +733,16 @@ namespace.append_obj( name="powerstrip_patch2", module_name="eco.devices_general.powersockets", ) + +## diffractometers +namespace.append_obj( + "AdjustableFS", + "/photonics/home/gac-bernina/eco/configuration/config_JFs", + module_name="eco.elements.adjustable", + lazy=True, + name="config_JFs", +) + namespace.append_obj( "GPS", module_name="eco.endstations.bernina_diffractometers", @@ -737,13 +752,19 @@ namespace.append_obj( fina_hex_angle_offset="/sf/bernina/config/eco/reference_values/hex_pi_angle_offset.json", lazy=True, ) + + namespace.append_obj( "XRDYou", module_name="eco.endstations.bernina_diffractometers", Id="SARES21-XRD", configuration=config_bernina.xrd_config(), - diff_detector={"jf_id": "JF01T03V01"}, + detectors=[ + {"name": "det_diff", "jf_id": "JF01T03V01"}, + {"name": "det_fluo", "jf_id": "JF04T01V01"}, + ], pgroup_adj=config_bernina.pgroup, + configsjf_adj=config_JFs, invert_kappa_ellbow=config_bernina.invert_kappa_ellbow._value, fina_hex_angle_offset="/sf/bernina/config/eco/reference_values/hex_pi_angle_offset.json", name="xrd", @@ -776,14 +797,7 @@ namespace.append_obj( ) namespace.append_obj( "AdjustableFS", - "/photonics/home/gac-bernina/eco/configuration/config_JFs", - module_name="eco.elements.adjustable", - lazy=True, - name="config_JFs", -) -namespace.append_obj( - "AdjustableFS", - "/photonics/home/gac-bernina/eco/configuration/channels_BS", + "/photonics/home/gac-bernina/eco/configuration/channTest of new scilog for Ovuka experimentels_BS", module_name="eco.elements.adjustable", lazy=True, name="channels_BS", @@ -818,54 +832,67 @@ namespace.append_obj( lazy=True, ) + namespace.append_obj( - "DetectorRobot", - JF_detector_id='JF01T03V01', - JF_detector_name='det_diff', + "Jungfrau", + "JF03T01V02", + name="det_i0", pgroup_adj=config_bernina.pgroup, - module_name="eco.endstations.bernina_robot", - name='robot', + module_name="eco.detector.jungfrau", + config_adj=config_JFs, + lazy=True, +) + +namespace.append_obj( + "DetectorRobot", + JF_detector_id="JF01T03V01", + JF_detector_name="det_diff", + pgroup_adj=config_bernina.pgroup, + config_adj=config_JFs, + module_name="eco.endstations.bernina_robot", + name="robot", +) + +namespace.append_obj( + "MpodModule", + "SARES21-CPCL-PS7071", + [1,2,3,4], + ['ch1','ch2','ch3','ch4'], + module_string='LV_OMPV_1', + name="power_LV_patch1", + module_name="eco.devices_general.powersockets", +) + +namespace.append_obj( + "MpodModule", + "SARES21-CPCL-PS7071", + [5,6,7,8], + ['ch1','ch2','ch3','ch4'], + module_string='LV_OMPV_1', + name="power_LV_patch2", + module_name="eco.devices_general.powersockets", ) -#namespace.append_obj( -# "MpodModule", -# "SARES21-CPCL-PS7071", -# [1,2,3,4], -# ['ch1','ch2','ch3','ch4'], -# module_string='LV_OMPV_1', -# name="power_LV_patch1", -# module_name="eco.devices_general.powersockets", -#) # -#namespace.append_obj( +# namespace.append_obj( # "MpodModule", # "SARES21-CPCL-PS7071", -# [5,6,7,8], -# ['ch1','ch2','ch3','ch4'], -# module_string='LV_OMPV_1', -# name="power_LV_patch2", -# module_name="eco.devices_general.powersockets", -#) -# -#namespace.append_obj( -# "MpodModule", -# "SARES21-CPCL-PS7071", -# [1,2,3,4], -# ['ch1','ch2','ch3','ch4'], -# module_string='HV_EHS_3', +# [1,2,3,4], +# ['ch1','ch2','ch3','ch4'], +# module_string='HV_EHS_3', # name="power_HV_patch1", # module_name="eco.devices_general.powersockets", -#) +# ) # -#namespace.append_obj( +# namespace.append_obj( # "MpodModule", # "SARES21-CPCL-PS7071", -# [5,6,7,8], -# ['ch1','ch2','ch3','ch4'], -# module_string='HV_EHS_3', +# [5,6,7,8], +# ['ch1','ch2','ch3','ch4'], +# module_string='HV_EHS_3', # name="power_HV_patch2", # module_name="eco.devices_general.powersockets", -#) +# ) ### draft new epics daq ### # namespace.append_obj( @@ -1031,10 +1058,13 @@ def _write_namespace_aliases_to_scan(scan, daq=daq, **kwargs): def _message_end_scan(scan, **kwargs): print(f"Finished run {scan.run_number}.") - e = pyttsx3.init() - e.say(f"Finished run {scan.run_number}.") - e.runAndWait() - e.stop() + try: + e = pyttsx3.init() + e.say(f"Finished run {scan.run_number}.") + e.runAndWait() + e.stop() + except: + print("Audio output failed.") # def _copy_scan_info_to_raw(scan, daq=daq): @@ -1368,10 +1398,10 @@ def _create_metadata_structure_start_scan( callbacks_start_scan.append(_create_metadata_structure_start_scan) namespace.append_obj( - 'CheckerCA', - module_name='eco.acquisition.checkers', - pvname='SLAAR21-LTIM01-EVR0:CALCI', - thresholds=[0.2,10], + "CheckerCA", + module_name="eco.acquisition.checkers", + pvname="SLAAR21-LTIM01-EVR0:CALCI", + thresholds=[0.2, 10], required_fraction=0.6, name="checker", ) @@ -1433,13 +1463,14 @@ namespace.append_obj( module_name="eco.devices_general.cameras_ptz", ) -namespace.append_obj( - "BerninaInlineMicroscope", - pvname_camera="SARES20-CAMS142-M3", - lazy=True, - name="samplecam_inline", - module_name="eco.microscopes", -) +# this is the large inline camera +# namespace.append_obj( +# "BerninaInlineMicroscope", +# pvname_camera="SARES20-CAMS142-M3", +# lazy=True, +# name="samplecam_inline", +# module_name="eco.microscopes", +# ) # namespace.append_obj( # "CameraBasler", @@ -1449,32 +1480,32 @@ namespace.append_obj( # module_name="eco.microscopes", # ) -#namespace.append_obj( +# namespace.append_obj( # "MicroscopeMotorRecord", # pvname_camera="SARES20-CAMS142-C1", # lazy=True, # name="samplecam", # module_name="eco.microscopes", # pvname_zoom="SARES20-MF1:MOT_5", -#) - -# namespace.append_obj( -# "MicroscopeMotorRecord", -# "SARES20-CAMS142-C1", -# lazy=True, -# pvname_zoom="SARES20-MF1:MOT_16", -# name="samplecam_microscope", -# module_name="eco.microscopes", # ) +namespace.append_obj( + "MicroscopeMotorRecord", + "SARES20-CAMS142-C1", + lazy=True, + pvname_zoom="SARES20-MF1:MOT_7", + name="samplecam_inline", + module_name="eco.microscopes", +) namespace.append_obj( "CameraBasler", - "SARES20-CAMS142-M2", + "SLAAR21-LCAM-C532", lazy=True, name="samplecam_sideview", module_name="eco.devices_general.cameras_swissfel", ) + # namespace.append_obj( # "CameraBasler", # "SARES20-CAMS142-C2", @@ -1492,7 +1523,6 @@ namespace.append_obj( # ) - # namespace.append_obj( # "CameraBasler", # "SARES20-CAMS142-C3", @@ -1550,11 +1580,11 @@ from ..loptics.bernina_laser import DelayTime namespace.append_obj( - "Organic_crystal_breadboard", - lazy=True, - name="ocb", - module_name="eco.endstations.bernina_sample_environments", - Id="SARES23", + "Organic_crystal_breadboard", + lazy=True, + name="ocb", + module_name="eco.endstations.bernina_sample_environments", + Id="SARES23", ) from ..epics.adjustable import AdjustablePv, AdjustablePvEnum @@ -1595,11 +1625,11 @@ from ..epics.adjustable import AdjustablePv, AdjustablePvEnum # ) -#namespace.append_obj( +# namespace.append_obj( # Double_Pulse_Pump, # lazy=True, # name="pump", -#) +# ) # ad hoc N2 jet readout @@ -1658,52 +1688,70 @@ class Incoupling(Assembly): self._append(SmaractRecord, "SARES23:ESB10", name="ver", is_setting=True) self._append(SmaractRecord, "SARES23:ESB13", name="hor", is_setting=True) self._append(SmaractRecord, "SARES23:ESB11", name="x", is_setting=True) - self._append(MotorRecord, "SLAAR21-LMOT-M521:MOTOR_1", name="delaystage_eos", is_setting=True,) - self._append(DelayTime, self.delaystage_eos, name="delay_eos", is_setting=False, is_display=True) - self._append(AdjustablePvEnum, "SLAAR21-LDIO-LAS6991:SET_BO02", name='eos_is_shut', is_setting=True) - self._append(DigitizerIoxosBoxcarChannel,"SARES20-LSCP9-FNS:CH1", - name=f"signal_pol0", - is_setting=True, - ) - self._append(DigitizerIoxosBoxcarChannel,"SARES20-LSCP9-FNS:CH3", - name=f"signal_pol1", - is_setting=True, - ) + self._append( + MotorRecord, + "SLAAR21-LMOT-M521:MOTOR_1", + name="delaystage_eos", + is_setting=True, + ) + self._append( + DelayTime, + self.delaystage_eos, + name="delay_eos", + is_setting=False, + is_display=True, + ) + self._append( + AdjustablePvEnum, + "SLAAR21-LDIO-LAS6991:SET_BO02", + name="eos_is_shut", + is_setting=True, + ) + self._append( + DigitizerIoxosBoxcarChannel, + "SARES20-LSCP9-FNS:CH1", + name=f"signal_pol0", + is_setting=True, + ) + self._append( + DigitizerIoxosBoxcarChannel, + "SARES20-LSCP9-FNS:CH3", + name=f"signal_pol1", + is_setting=True, + ) namespace.append_obj( Incoupling, lazy=True, - name="eos", + name="las_inc", ) -class Jungfraus(Assembly): - def __init__(self, name=None): - super().__init__(name=name) - self._append( - Jungfrau, "JF07T32V02", pgroup_adj=config_bernina.pgroup, name="diff" - ) - self._append( - Jungfrau, "JF03T01V02", name="i0", pgroup_adj=config_bernina.pgroup - ) -namespace.append_obj( - Jungfraus, - lazy=True, - name="jfs", -) -namespace.append_obj( - "High_field_thz_chamber", - name="thc", - lazy=True, - module_name="eco.endstations.bernina_sample_environments", - illumination_mpod = [{'pvbase':'SARES21-CPCL-PS7071' ,'channel_number':5 ,'module_string':'LV_OMPV_1' ,'name': 'illumination'}], - helium_control_valve = {'pvbase':'SARES21-CPCL-PS7071' ,'channel_number':4 ,'module_string':'LV_OMPV_1' ,'name': 'helium_control_valve'}, - # configuration=["ottifant"], - configuration=[], -) +# namespace.append_obj( +# "High_field_thz_chamber", +# name="thc", +# lazy=True, +# module_name="eco.endstations.bernina_sample_environments", +# illumination_mpod=[ +# { +# "pvbase": "SARES21-CPCL-PS7071", +# "channel_number": 5, +# "module_string": "LV_OMPV_1", +# "name": "illumination", +# } +# ], +# helium_control_valve={ +# "pvbase": "SARES21-CPCL-PS7071", +# "channel_number": 4, +# "module_string": "LV_OMPV_1", +# "name": "helium_control_valve", +# }, +# # configuration=["ottifant"], +# configuration=[], +# ) # class Sample_stages(Assembly): # def __init__(self, name=None): @@ -1735,76 +1783,79 @@ namespace.append_obj( # self._append(SmaractRecord, "SARES23:ESB9", name="mirr_rz", is_setting=True) # self._append(SmaractRecord, "SARES23:LIC15", name="polarizer", is_setting=True) -class THzVirtualStages(Assembly): - def __init__(self, name=None, mx=None, mz=None, px=None, pz=None): - super().__init__(name=name) - self._mx = mx - self._mz = mz - self._px = px - self._pz = pz - self._append( - AdjustableFS, - "/photonics/home/gac-bernina/eco/configuration/p21145_mirr_x0", - name="offset_mirr_x", - default_value=0, - is_setting=True, - ) - self._append( - AdjustableFS, - "/photonics/home/gac-bernina/eco/configuration/p21145_mirr_z0", - name="offset_mirr_z", - default_value=0, - is_setting=True, - ) - self._append( - AdjustableFS, - "/photonics/home/gac-bernina/eco/configuration/p21145_par_x0", - name="offset_par_x", - default_value=0, - is_setting=True, - ) - self._append( - AdjustableFS, - "/photonics/home/gac-bernina/eco/configuration/p21145_par_z0", - name="offset_par_z", - default_value=0, - is_setting=True, - ) - def get_divergence(mx, px): - return px - self.offset_par_x() - def set_divergence(x): - mx = self.offset_mirr_x() + x - px = self.offset_par_x() + x - return mx,px +# class THzVirtualStages(Assembly): +# def __init__(self, name=None, mx=None, mz=None, px=None, pz=None): +# super().__init__(name=name) +# self._mx = mx +# self._mz = mz +# self._px = px +# self._pz = pz +# self._append( +# AdjustableFS, +# "/photonics/home/gac-bernina/eco/configuration/p21145_mirr_x0", +# name="offset_mirr_x", +# default_value=0, +# is_setting=True, +# ) +# self._append( +# AdjustableFS, +# "/photonics/home/gac-bernina/eco/configuration/p21145_mirr_z0", +# name="offset_mirr_z", +# default_value=0, +# is_setting=True, +# ) +# self._append( +# AdjustableFS, +# "/photonics/home/gac-bernina/eco/configuration/p21145_par_x0", +# name="offset_par_x", +# default_value=0, +# is_setting=True, +# ) +# self._append( +# AdjustableFS, +# "/photonics/home/gac-bernina/eco/configuration/p21145_par_z0", +# name="offset_par_z", +# default_value=0, +# is_setting=True, +# ) - def get_focus_z(mx, pz): - return pz - self.offset_par_z() - def set_focus_z(z): - mz = self.offset_mirr_z() + z - pz = self.offset_par_z() + z - return mz, pz - self._append( - AdjustableVirtual, - [mx, px], - get_divergence, - set_divergence, - name="divergence_virtual", - ) - self._append( - AdjustableVirtual, - [mz, pz], - get_focus_z, - set_focus_z, - name="focus_virtual", - ) - def set_offsets_to_current_value(self): - self.offset_mirr_x.mv(self._mx()) - self.offset_mirr_z.mv(self._mz()) - self.offset_par_x.mv(self._px()) - self.offset_par_z.mv(self._pz()) +# def get_divergence(mx, px): +# return px - self.offset_par_x() +# def set_divergence(x): +# mx = self.offset_mirr_x() + x +# px = self.offset_par_x() + x +# return mx, px +# def get_focus_z(mx, pz): +# return pz - self.offset_par_z() + +# def set_focus_z(z): +# mz = self.offset_mirr_z() + z +# pz = self.offset_par_z() + z +# return mz, pz + +# self._append( +# AdjustableVirtual, +# [mx, px], +# get_divergence, +# set_divergence, +# name="divergence_virtual", +# ) +# self._append( +# AdjustableVirtual, +# [mz, pz], +# get_focus_z, +# set_focus_z, +# name="focus_virtual", +# ) + +# def set_offsets_to_current_value(self): +# self.offset_mirr_x.mv(self._mx()) +# self.offset_mirr_z.mv(self._mz()) +# self.offset_par_x.mv(self._px()) +# self.offset_par_z.mv(self._pz()) # class THz(Assembly): @@ -1816,20 +1867,19 @@ class THzVirtualStages(Assembly): # self._append(SmaractRecord, "SARES23:LIC14", name="par_rx", is_setting=True) # self._append(SmaractRecord, "SARES23:ESB15", name="par_ry", is_setting=True) # self._append(SmaractRecord, "SARES23:ESB1", name="delaystage_thz", is_setting=True,) -# self._append(DelayTime, self.delaystage_thz, name="delay_thz", is_setting=False, is_display=True,) +# self._append(DelayTime, self.delaystage_thz, name="delay_thz", is_setting=False, is_display=True,) # self._append(LaserSteering, name="ir_pointing", is_setting=False) # self._append(THzGeneration, name="generation", is_setting=False) - - ### Virtual stages ### - # self._append( - # THzVirtualStages, - # name="virtual_stages", - # mx=self.generation.mirr_x, - # mz=self.generation.mirr_z, - # px=self.generation.par_x, - # pz = self.par_z, - # is_setting=False) +### Virtual stages ### +# self._append( +# THzVirtualStages, +# name="virtual_stages", +# mx=self.generation.mirr_x, +# mz=self.generation.mirr_z, +# px=self.generation.par_x, +# pz = self.par_z, +# is_setting=False) # namespace.append_obj( @@ -1936,7 +1986,6 @@ class THzVirtualStages(Assembly): # ) - namespace.append_obj( "SmaractController", "SARES23:LIC", @@ -2071,7 +2120,6 @@ from ..microscopes import MicroscopeMotorRecord # ) - namespace.append_obj( "SwissFel", name="fel", @@ -2154,6 +2202,8 @@ namespace.append_obj( ############## experiment specific ############# from eco.loptics.bernina_laser import Stage_LXT_Delay + + class Laser_Xray_Timing(Assembly): def __init__(self, name=None): super().__init__(name=name) @@ -2165,6 +2215,7 @@ class Laser_Xray_Timing(Assembly): name="delay", ) + namespace.append_obj( Laser_Xray_Timing, lazy=True, @@ -2226,7 +2277,7 @@ namespace.append_obj( # ) # thz._append(Stage_LXT_Delay, thz.delay_thz, "/photonics/home/gac-bernina/eco/configuration/p21145_delay_stage_offset", name="delay_thz_phase_shifter", is_setting=False, is_display=True,) -# thz._append(Stage_LXT_Delay, eos.delay_eos, "/photonics/home/gac-bernina/eco/configuration/p21145_delayeos_stage_offset", name="delay_eos_phase_shifter", is_setting=False, is_display=True,) +# thz._append(Stage_LXT_Delay, eos.delay_eos, "/photonics/home/gac-bernina/eco/configuration/p21145_delayeos_stage_offset", name="delay_eos_phase_shifter", is_setting=False, is_display=True,) # # self.combined_delay = AdjustableVirtual( # # [self.delay_thz, self.delay_800_pump], @@ -2242,7 +2293,7 @@ namespace.append_obj( # return 1.0 * val2 -#namespace.append_obj( +# namespace.append_obj( # "Bernina_XEYE", # zoomstage_pv=config_bernina.xeye.zoomstage_pv._value, # camera_pv=config_bernina.xeye.camera_pv._value, @@ -2251,7 +2302,7 @@ namespace.append_obj( # name="xeye", # lazy=True, # module_name="eco.xdiagnostics.profile_monitors", -#) +# ) # try to append pgroup folder to path !!!!! This caused eco to run in a timeout without error traceback !!!!! try: @@ -2269,7 +2320,7 @@ try: "Could not access experiment folder, could be due to more systematic file system failure!" ) except: - print("Did not succed to append an eco folder in current prgoup") + print("Did not succeed to append an eco folder in current prgoup") class Xspect_EH55(Assembly): @@ -2319,62 +2370,91 @@ namespace.append_obj( lazy=True, ) +## N2 sample heater setup -from eco.devices_general.wago import AnalogOutput -from eco.detector import Jungfrau -from eco.timing.event_timing_new_new import EvrOutput -from eco.devices_general.digitizers import DigitizerIoxosBoxcarChannel -from eco.elements.adjustable import AdjustableVirtual -import numpy as np - - -class LiquidJetSpectroscopy(Assembly): - def __init__(self, name=None): +from eco.devices_general.env_sensors import WagoSensor +class SampleHeaterJet(Assembly): + def __init__(self,name='sampleheaterjet'): super().__init__(name=name) - self._append( - MotorRecord, - "SARES20-MF1:MOT_2", - name="x_jet", - backlash_definition=True, - is_setting=True, - ) - self._append( - MotorRecord, - "SARES20-MF1:MOT_4", - name="y_jet", - backlash_definition=True, - is_setting=True, - ) - self._append( - MotorRecord, - "SARES20-MF1:MOT_6", - name="z_jet", - backlash_definition=True, - is_setting=True, - ) - self._append( - MotorRecord, - "SARES20-MF1:MOT_3", - name="x_analyzer", - backlash_definition=True, - is_setting=True, - ) - self._append( - MotorRecord, - "SARES21-XRD:MOT_P_T", - name="y_vhdet", - is_setting=True, - ) - self._append( - Jungfrau, "JF03T01V02", name="det_i0", pgroup_adj=config_bernina.pgroup - ) - self._append( - Jungfrau, "JF04T01V01", name="det_em", pgroup_adj=config_bernina.pgroup - ) - self._append( - Jungfrau, "JF14T01V01", name="det_vhamos", pgroup_adj=config_bernina.pgroup - ) - self._append(CameraBasler, "SARES20-CAMS142-M2", name="prof_pump") + self._append(WagoSensor,pvbase='SARES20-CWAG-GPS01:TEMP-T9', name='sensor_sample') + self._append(WagoSensor,pvbase='SARES20-CWAG-GPS01:TEMP-T10', name='sensor_jet_mount') + self._append(WagoSensor,pvbase='SARES20-CWAG-GPS01:TEMP-T11', name='sensor_hexapod') + + +namespace.append_obj(SampleHeaterJet, name="heater_jet", lazy=True) + + +## sample illumination +from eco.devices_general.powersockets import MpodChannel +class IlluminatorsLasers(Assembly): + def __init__(self,name='sample_illumination'): + super().__init__(name=name) + self._append(MpodChannel,pvbase='SARES21-CPCL-PS7071', channel_number=2, name='illumination_1') + self._append(MpodChannel,pvbase='SARES21-CPCL-PS7071', channel_number=2, name='flattening_laser') + + +namespace.append_obj(IlluminatorsLasers, name="sample_illumination", lazy=True) + + + + +## LIQUID jet setup + +# from eco.devices_general.wago import AnalogOutput +# from eco.detector import Jungfrau +# from eco.timing.event_timing_new_new import EvrOutputsample +# from eco.devices_general.digitizers import DigitizerIoxosBoxcarChannel +# from eco.elements.adjustable import AdjustableVirtual +# import numpy as np + + +# class LiquidJetSpectroscopy(Assembly): +# def __init__(self, name=None): +# super().__init__(name=name) +# self._append( +# MotorRecord, +# "SARES20-MF1:MOT_2", +# name="x_jet", +# backlash_definition=True, +# is_setting=True, +# ) +# self._append( +# MotorRecord, +# "SARES20-MF1:MOT_4", +# name="y_jet", +# backlash_definition=True, +# is_setting=True, +# ) +# self._append( +# MotorRecord, +# "SARES20-MF1:MOT_6", +# name="z_jet", +# backlash_definition=True, +# is_setting=True, +# ) +# self._append( +# MotorRecord, +# "SARES20-MF1:MOT_3", +# name="x_analyzer", +# backlash_definition=True, +# is_setting=True, +# ) +# self._append( +# MotorRecord, +# "SARES21-XRD:MOT_P_T", +# name="y_vhdet", +# is_setting=True, +# ) +# self._append( +# Jungfrau, "JF03T01V02", name="det_i0", pgroup_adj=config_bernina.pgroup +# ) +# self._append( +# Jungfrau, "JF04T01V01", name="det_em", pgroup_adj=config_bernina.pgroup +# ) +# self._append( +# Jungfrau, "JF14T01V01", name="det_vhamos", pgroup_adj=config_bernina.pgroup +# ) +# self._append(CameraBasler, "SARES20-CAMS142-M2", name="prof_pump") # namespace.append_obj(LiquidJetSpectroscopy, name="jet", lazy=True) @@ -2496,7 +2576,54 @@ class LiquidJetSpectroscopy(Assembly): # "desc": "LiNbO3 crystal breadboard", # "type": "eco.endstations.bernina_sample_environments:LiNbO3_crystal_breadboard", # "kwargs": {"Id": "SARES23"}, -# }, +# },class LiquidJetSpectroscopy(Assembly): +# def __init__(self, name=None): +# super().__init__(name=name) +# self._append( +# MotorRecord, +# "SARES20-MF1:MOT_2", +# name="x_jet", +# backlash_definition=True, +# is_setting=True, +# ) +# self._append( +# MotorRecord, +# "SARES20-MF1:MOT_4", +# name="y_jet", +# backlash_definition=True, +# is_setting=True, +# ) +# self._append( +# MotorRecord, +# "SARES20-MF1:MOT_6", +# name="z_jet", +# backlash_definition=True, +# is_setting=True, +# ) +# self._append( +# MotorRecord, +# "SARES20-MF1:MOT_3", +# name="x_analyzer", +# backlash_definition=True, +# is_setting=True, +# ) +# self._append( +# MotorRecord, +# "SARES21-XRD:MOT_P_T", +# name="y_vhdet", +# is_setting=True, +# ) +# self._append( +# Jungfrau, "JF03T01V02", name="det_i0", pgroup_adj=config_bernina.pgroup +# ) +# self._append( +# Jungfrau, "JF04T01V01", name="det_em", pgroup_adj=config_bernina.pgroup +# ) +# self._append( +# Jungfrau, "JF14T01V01", name="det_vhamos", pgroup_adj=config_bernina.pgroup +# ) +# self._append(CameraBasler, "SARES20-CAMS142-M2", name="prof_pump") + # { # "args": [], # "name": "vonHamos", @@ -2531,26 +2658,32 @@ def pgroup2name(pgroup): return names[targets.index(pgroup)] -def name2pgroups(name): - tp = "/sf/bernina/exp/" +def name2pgroups(name, beamline="bernina"): + tp = f"/sf/{beamline}/exp/" d = Path(tp) dirs = [i for i in d.glob("*") if i.is_symlink()] names = [i.name for i in dirs] targets = [i.resolve().name for i in dirs] - return [[i_n, i_p] for i_n, i_p in zip(names, targets) if name in i_n] + eq = [[i_n, i_p] for i_n, i_p in zip(names, targets) if name == i_n] + ni = [ + [i_n, i_p] + for i_n, i_p in zip(names, targets) + if (not name == i_n) and (name in i_n) + ] + return eq + ni -#namespace.append_obj( +# namespace.append_obj( # "Jungfrau", # "JF03T01V02", # name="det_i0", # pgroup_adj=config_bernina.pgroup, # module_name="eco.detector", -#) -#namespace.append_obj( +# ) +# namespace.append_obj( # "Jungfrau", # "JF01T03V01", # name="data", # pgroup_adj=config_bernina.pgroup, # module_name="eco.detector", -#) +# ) diff --git a/eco/detector/jungfrau.py b/eco/detector/jungfrau.py index 0cd47fb..fb92b95 100644 --- a/eco/detector/jungfrau.py +++ b/eco/detector/jungfrau.py @@ -207,6 +207,15 @@ class JungfrauDaqConfig(Assembly): is_display=True, is_setting=True, ) + self._append( + AdjustableGetSet, + self._get_geometry_corr, + self._set_geometry_corr, + name="apply_tile_geometry", + is_display=True, + is_setting=True, + ) + self._append( AdjustableGetSet, self._get_compressed_bitshuffle, @@ -239,6 +248,14 @@ class JungfrauDaqConfig(Assembly): is_display=True, is_setting=True, ) + self._append( + AdjustableGetSet, + self._get_disabled_modules, + self._set_disabled_modules, + name="disabled_tiles", + is_display=True, + is_setting=True, + ) def _get_adc_to_energy(self, *args): try: @@ -256,6 +273,22 @@ class JungfrauDaqConfig(Assembly): cfg[self._jf_id]["adc_to_energy"] = False self._jf_daq_cfg.set_target_value(cfg).wait() + def _get_geometry_corr(self, *args): + try: + return self._jf_daq_cfg.get_current_value()[self._jf_id]["geometry"] + except KeyError: + return "not sure what happens" + + def _set_geometry_corr(self, value): + if value: + cfg = self._jf_daq_cfg.get_current_value() + cfg[self._jf_id]["geometry"] = True + self._jf_daq_cfg.set_target_value(cfg).wait() + else: + cfg = self._jf_daq_cfg.get_current_value() + cfg[self._jf_id]["adc_to_energy"] = False + self._jf_daq_cfg.set_target_value(cfg).wait() + def _get_compressed_bitshuffle(self, *args): try: return self._jf_daq_cfg.get_current_value()[self._jf_id]["compression"] @@ -316,3 +349,62 @@ class JungfrauDaqConfig(Assembly): cfg = self._jf_daq_cfg.get_current_value() cfg[self._jf_id]["factor"] = value self._jf_daq_cfg.set_target_value(cfg).wait() + + def _get_disabled_modules(self, *args): + try: + return self._jf_daq_cfg.get_current_value()[self._jf_id]["disabled_modules"] + except KeyError: + return [] + + def _set_disabled_modules(self, value): + cfg = self._jf_daq_cfg.get_current_value() + if value == []: + cfg[self._jf_id].pop("disabled_modules") + else: + cfg[self._jf_id]["disabled_modules"] = value + self._jf_daq_cfg.set_target_value(cfg).wait() + + def _get_binning(self, *args): + try: + return self._jf_daq_cfg.get_current_value()[self._jf_id]["downsample"] + except KeyError: + return [1, 1] + + def _set_binning(self, value): + cfg = self._jf_daq_cfg.get_current_value() + if value == [1, 1]: + cfg[self._jf_id].pop("downsample") + else: + cfg[self._jf_id]["downsample"] = value + self._jf_daq_cfg.set_target_value(cfg).wait() + + def _get_keepraw(self, *args): + try: + remove_raw = self._jf_daq_cfg.get_current_value()[self._jf_id][ + "remove_raw_files" + ] + # if type(remove_raw) is bool: + return remove_raw + + except KeyError: + return "not sure what happens" + + def _set_keepraw(self, value): + cfg = self._jf_daq_cfg.get_current_value() + cfg[self._jf_id]["remove_raw_files"] = value + self._jf_daq_cfg.set_target_value(cfg).wait() + + +# { +# "adc_to_energy": true, +# "compression": true, +# "double_pixels_actions": "interpolate", +# "downsample": [ +# 1, +# 1 +# ], +# "factor": 0.25,x +# "geometry": true, +# "remove_raw_files": false +#   "disabled_modules": [], +# }, diff --git a/eco/devices_general/env_sensors.py b/eco/devices_general/env_sensors.py index 7d0c65d..3f6ae94 100644 --- a/eco/devices_general/env_sensors.py +++ b/eco/devices_general/env_sensors.py @@ -1,6 +1,6 @@ from eco import Assembly from eco.epics.adjustable import AdjustablePv, AdjustablePvEnum, AdjustablePvString -from eco.epics.detector import DetectorPvData +from eco.epics.detector import DetectorPvData, DetectorPvEnum from epics import PV @@ -51,3 +51,17 @@ class BerninaEnvironment(Assembly): self._append(I2cChannel,pvbase,channelnumber=n,name=tname) +class WagoSensor(Assembly): + def __init__(self,pvbase='SARES20-CWAG-GPS01:TEMP-T9', name=None): + super().__init__(name=name) + self.pvbase = pvbase + self._append(DetectorPvData,f'{self.pvbase}', unit='°C', name='temperature') + self._append(DetectorPvEnum,f'{self.pvbase}-SS', name='status') + self._append(AdjustablePv,f'{self.pvbase}-WLEN', name='cable_length', unit='m', is_setting=True) + self.unit = self.temperature.unit + + def get_current_value(self): + return self.temperature.get_current_value() + + + diff --git a/eco/elements/memory.py b/eco/elements/memory.py index e5cb6fc..af02ccb 100644 --- a/eco/elements/memory.py +++ b/eco/elements/memory.py @@ -84,6 +84,8 @@ class Memory: tmp = AdjustableFS(self.dir / Path(key + ".json")) tmp(stat_now) self._memories(mem) + print(f"Saved memory for {self.obj_parent.alias.get_full_name()}: {message}") + print(f"memory file: {tmp.file_path.as_posix()}") def get_memory(self, input_obj=None, index=None, key=None, filter_existing=True): if not input_obj is None: @@ -116,6 +118,15 @@ class Memory: else: return mem_full + def clear_memory(self, index=None, key=None): + if not (index is None): + key = list(self._memories().keys())[index] + if key is None: + raise Exception("memory key or index to be deleted needs to be specified!") + mem = self._memories.get_current_value() + mem.pop(key) + self._memories.set_target_value(mem).wait() + def recall( self, memory_index=None, @@ -128,6 +139,23 @@ class Memory: change_serially=False, force=False, ): + """Recall a memory_index, from an index in the default meory list, from a + dictionary containing the memory information, or from a path to a file containing the memory. + + Args: + memory_index (integer, optional): index in memory list. Defaults to None. + input_obj (dictionary or string, optional): direct passing memory as dict or s filepath (string) to the memory file. Defaults to None. + key (string, optional): key of memory in memory list (if not defined by the index). Defaults to None. + wait (bool, optional): Wait for the memory recall changes to complete. Defaults to True. + show_changes_only (bool, optional): in rpreview show only changes that are different to present setting. Defaults to True. + set_changes_only (bool, optional): setting only the changes that changed. Defaults to True. + check_limits (bool, optional): check limits before changing. Defaults to True. + change_serially (bool, optional): change and wait each change after each other, not simultaneously. Defaults to False. + force (bool, optional): force the change without previous preview. Defaults to False. + + Returns: + _type_: _description_ + """ # if input_obj: mem = self.get_memory( index=memory_index, @@ -233,7 +261,6 @@ class Memory: def select_from_memory( self, input_obj=None, key=None, memory_index=None, show_changes_only=True ): - mem = self.get_memory(input_obj=input_obj, key=key, index=memory_index) rec = mem["settings"] k = KeyPress() @@ -388,7 +415,6 @@ class Preset: return s def __repr__(self): - return self.__str__() diff --git a/eco/endstations/bernina_diffractometers.py b/eco/endstations/bernina_diffractometers.py index f09490f..aa9e30d 100644 --- a/eco/endstations/bernina_diffractometers.py +++ b/eco/endstations/bernina_diffractometers.py @@ -138,7 +138,6 @@ class GPS(Assembly): ) if "phi_hex" in self.configuration: - ### motors PI hexapod ### if fina_hex_angle_offset: fina_hex_angle_offset = Path(fina_hex_angle_offset).expanduser() @@ -285,7 +284,6 @@ class GPS(Assembly): is_display=False, ) - def gui(self, guiType="xdm"): """Adjustable convention""" cmd = ["caqtdm", "-macro"] @@ -412,9 +410,10 @@ class XRDYou(Assembly): name=None, Id=None, configuration=["base"], - diff_detector=None, + detectors=None, invert_kappa_ellbow=True, pgroup_adj=None, + configsjf_adj=None, fina_hex_angle_offset=None, diffcalc=True, ): @@ -608,7 +607,6 @@ class XRDYou(Assembly): ) if "phi_hex" in self.configuration: - ### motors PI hexapod ### if fina_hex_angle_offset: fina_hex_angle_offset = Path(fina_hex_angle_offset).expanduser() @@ -621,50 +619,50 @@ class XRDYou(Assembly): is_setting=True, is_display="recursive", ) -# if "phi_hex" in self.configuration: -# ### motors PI hexapod ### -# append_object_to_object( -# self, -# AdjustablePv, -# "SARES20-HEX_PI:SET-POSI-X", -# pvreadbackname="SARES20-HEX_PI:POSI-X", -# name="xhex", -# ) -# append_object_to_object( -# self, -# AdjustablePv, -# "SARES20-HEX_PI:SET-POSI-Y", -# pvreadbackname="SARES20-HEX_PI:POSI-Y", -# name="yhex", -# ) -# append_object_to_object( -# self, -# AdjustablePv, -# "SARES20-HEX_PI:SET-POSI-Z", -# pvreadbackname="SARES20-HEX_PI:POSI-Z", -# name="zhex", -# ) -# append_object_to_object( -# self, -# AdjustablePv, -# "SARES20-HEX_PI:SET-POSI-U", -# pvreadbackname="SARES20-HEX_PI:POSI-U", -# name="uhex", -# ) -# append_object_to_object( -# self, -# AdjustablePv, -# "SARES20-HEX_PI:SET-POSI-V", -# pvreadbackname="SARES20-HEX_PI:POSI-V", -# name="vhex", -# ) -# append_object_to_object( -# self, -# AdjustablePv, -# "SARES20-HEX_PI:SET-POSI-W", -# pvreadbackname="SARES20-HEX_PI:POSI-W", -# name="whex", -# ) + # if "phi_hex" in self.configuration: + # ### motors PI hexapod ### + # append_object_to_object( + # self, + # AdjustablePv, + # "SARES20-HEX_PI:SET-POSI-X", + # pvreadbackname="SARES20-HEX_PI:POSI-X", + # name="xhex", + # ) + # append_object_to_object( + # self, + # AdjustablePv, + # "SARES20-HEX_PI:SET-POSI-Y", + # pvreadbackname="SARES20-HEX_PI:POSI-Y", + # name="yhex", + # ) + # append_object_to_object( + # self, + # AdjustablePv, + # "SARES20-HEX_PI:SET-POSI-Z", + # pvreadbackname="SARES20-HEX_PI:POSI-Z", + # name="zhex", + # ) + # append_object_to_object( + # self, + # AdjustablePv, + # "SARES20-HEX_PI:SET-POSI-U", + # pvreadbackname="SARES20-HEX_PI:POSI-U", + # name="uhex", + # ) + # append_object_to_object( + # self, + # AdjustablePv, + # "SARES20-HEX_PI:SET-POSI-V", + # pvreadbackname="SARES20-HEX_PI:POSI-V", + # name="vhex", + # ) + # append_object_to_object( + # self, + # AdjustablePv, + # "SARES20-HEX_PI:SET-POSI-W", + # pvreadbackname="SARES20-HEX_PI:POSI-W", + # name="whex", + # ) if "kappa" in self.configuration: self._append( @@ -786,16 +784,21 @@ class XRDYou(Assembly): unit="deg", ) - if diff_detector: - self._append( - Jungfrau, - diff_detector["jf_id"], - name="det_diff", - is_setting=False, - is_display=False, - pgroup_adj=pgroup_adj, - view_toplevel_only=True, - ) + if detectors: + for tdet in detectors: + tname = tdet["name"] + tid = tdet["jf_id"] + self._append( + Jungfrau, + tid, + name=tname, + is_setting=False, + is_display=False, + pgroup_adj=pgroup_adj, + config_adj=configsjf_adj, + view_toplevel_only=True, + ) + if diffcalc: self._append( Crystals, diff --git a/eco/endstations/bernina_robot.py b/eco/endstations/bernina_robot.py index 09b03dd..b84f92f 100644 --- a/eco/endstations/bernina_robot.py +++ b/eco/endstations/bernina_robot.py @@ -1,9 +1,21 @@ from eco import Assembly from eco.detector.jungfrau import Jungfrau -class DetectorRobot(Assembly): - def __init__(self,JF_detector_id=None, JF_detector_name='det_diff', name='robot', pgroup_adj=None): - super().__init__(name=name) - self._append(Jungfrau,JF_detector_id,pgroup_adj=pgroup_adj, name=JF_detector_name) - \ No newline at end of file +class DetectorRobot(Assembly): + def __init__( + self, + JF_detector_id=None, + JF_detector_name="det_diff", + name="robot", + pgroup_adj=None, + config_adj=None, + ): + super().__init__(name=name) + self._append( + Jungfrau, + JF_detector_id, + pgroup_adj=pgroup_adj, + config_adj=config_adj, + name=JF_detector_name, + ) diff --git a/eco/epics/adjustable.py b/eco/epics/adjustable.py index a9fe229..4800c9f 100644 --- a/eco/epics/adjustable.py +++ b/eco/epics/adjustable.py @@ -16,6 +16,111 @@ from eco.devices_general.utilities import Changer from ..elements.assembly import Assembly + +# Work in progress! TODO +@spec_convenience +@get_from_archive +@tweak_option +@value_property +class AdjustableAtomicPv: + def __init__( + self, + pvsetname, + ): + # alias_fields={"setpv": pvsetname, "readback": pvreadbackname}, + # ): + self.pvname = pvsetname + self.name = name + # for an, af in alias_fields.items(): + # self.alias.append( + # Alias(an, channel=".".join([pvname, af]), channeltype="CA") + # ) + + self._pv = PV(self.pvname, connection_timeout=0.05, count=element_count) + self._currentChange = None + self.accuracy = accuracy + + if pvreadbackname is None: + self._pvreadback = PV(self.pvname, count=element_count, connection_timeout=0.05) + pvreadbackname = self.pvname + self.pvname = self.pvname + else: + self._pvreadback = PV( + pvreadbackname, count=element_count, connection_timeout=0.05 + ) + self.pvname = pvreadbackname + + if pvlowlimname: + self._pvlowlim = PV( + pvlowlimname, count=element_count, connection_timeout=0.05 + ) + else: + self._pvlowlim = None + if pvhighlimname: + self._pvhighlim = PV( + pvhighlimname, count=element_count, connection_timeout=0.05 + ) + else: + self._pvhighlim = None + self.alias = Alias(name, channel=pvreadbackname, channeltype="CA") + + def _wait_for_initialisation(self): + self._pv.wait_for_connection() + if hasattr(self, "_pv_readback") and self._pv_readback: + self._pv_readback.wait_for_connection() + if hasattr(self, "_pv_lowliself.accuracy = accuracym") and self._pv_lowlim: + self._pv_lowlim.wait_for_connection() + if hasattr(self, "_pv_highlim") and self._pv_highlim: + self._pv_highlim.wait_for_connection() + + def get_current_value(self, readback=True): + if readback: + currval = self._pvreadback.get() + if not readback: + currval = self._pv.get() + return currval + + def get_change_done(self): + """Adjustable convention""" + """ 0: moving 1: move done""" + change_done = 1 + if self.accuracy is not None: + if ( + np.abs( + self.get_current_value(readback=False) + - self.get_current_value(readback=True) + ) + > self.accuracy + ): + change_done = 0 + return change_done + + def change(self, value): + if self._pvlowlim: + if value < self._pvlowlim.get(): + raise Exception( + f"Target value of {self.name} is smaller than limit value!" + ) + if self._pvhighlim: + if self._pvhighlim.get() < value: + raise Exception( + f"Target value of {self.name} is higher than limit value!" + ) + + self._pv.put(value) + time.sleep(0.1) + while self.get_change_done() == 0: + time.sleep(0.1) + + def set_target_value(self, value, hold=False): + """Adjustable convention""" + + changer = lambda value: self.change(value) + return Changer( + target=value, parent=self, changer=changer, hold=hold, stopper=None + ) + + @spec_convenience @get_from_archive @tweak_option @@ -164,8 +269,8 @@ class AdjustablePvEnum: if pvname_set: self._pv_set = PV(pvname_set, connection_timeout=0.05) tstrs = self._pv_set.enum_strs - if not (tstrs == self.enum_strs): - raise Exception("pv enum setter strings do not match the values!") + if not all([tstr in self.enum_strs for tstr in tstrs]): + raise Exception("pv enum setter strings are not all a readback option!") else: self._pv_set = None diff --git a/eco/fel/swissfel.py b/eco/fel/swissfel.py index 1de5a4e..33617cb 100644 --- a/eco/fel/swissfel.py +++ b/eco/fel/swissfel.py @@ -68,7 +68,8 @@ class SwissFel(Assembly): # SAR-EVPO-010:DEACTIVATE "FALSE" self._append( AdjustablePvEnum, - "SAROP-ARAMIS:BEAMLINE_SP", + "SAROP-ARAMIS:BEAMLINE", + pvname_set = "SAROP-ARAMIS:BEAMLINE_SP", name="aramis_beamline_switch", is_display=True, is_setting=True, diff --git a/eco/utilities/elog_scilog.py b/eco/utilities/elog_scilog.py index 497d1ec..6191b33 100755 --- a/eco/utilities/elog_scilog.py +++ b/eco/utilities/elog_scilog.py @@ -1,4 +1,5 @@ -from scilog import SciLog +from markdown import markdown +from scilog import SciLog, LogbookMessage from getpass import getuser as _getuser from getpass import getpass as _getpass import os, datetime, subprocess @@ -26,7 +27,8 @@ def getDefaultElogInstance( print("Enter scilog password for user: %s" % kwargs["user"]) _pw = _getpass() kwargs.update(dict(password=_pw)) - log = SciLog(url, options={"username": user, "password": kwargs["password"]}) + log = SciLog(url, options := {"username": user, "password": kwargs["password"]}) + print(options) if pgroup: lbs = log.get_logbooks(ownerGroup=pgroup) if len(lbs) > 1: @@ -36,21 +38,40 @@ def getDefaultElogInstance( class Elog: - def __init__(self, url, screenshot_directory="", **kwargs): - self._log, self.user = getDefaultElogInstance(url, **kwargs) + def __init__( + self, + url="https://scilog.psi.ch/api/v1", + pgroup=None, + screenshot_directory="", + **kwargs, + ): + self._log, self.user = getDefaultElogInstance(url, pgroup=pgroup, **kwargs) self._screenshot = Screenshot(screenshot_directory) # self.read = self._log.read - def post(self, *args, Title=None, Author=None, Encoding="html", **kwargs): + def post(self, *args, tags=[], text_encoding="markdown", **kwargs): """ """ - if Encoding == "html": - args = list(args) - args[0] = args[0].replace("\n", "
\n") - if not Author: - Author = self.user - return self._log.post( - *args, Title=Title, Author=Author, Encoding=Encoding, **kwargs - ) + msg = LogbookMessage() + for targ in args: + if not ((type(targ) is str) or isinstance(targ, Path)): + raise Exception("Log messages should be of type string!") + + try: + print("trying file") + if Path(targ).expanduser().exists(): + print("file exists") + msg.add_file(targ) + except: + print("this is text") + if text_encoding == "markdown": + print("markdown warning") + msg.add_text(markdown(targ)) + else: + msg.add_text(targ) + for tag in tags: + msg.add_tag(tag) + + self._log.send_logbook_message(msg) def screenshot(self, message="", window=False, desktop=False, delay=3, **kwargs): filepath = self._screenshot.shoot()[0] diff --git a/eco/xdiagnostics/profile_monitors.py b/eco/xdiagnostics/profile_monitors.py index c9e1def..1e559e5 100755 --- a/eco/xdiagnostics/profile_monitors.py +++ b/eco/xdiagnostics/profile_monitors.py @@ -1,3 +1,4 @@ +from eco.detector.detectors_psi import DetectorBsStream from ..devices_general.motors import MotorRecord, SmaractStreamdevice, SmaractRecord from ..devices_general.detectors import CameraCA, CameraBS from ..devices_general.cameras_swissfel import CameraBasler @@ -15,7 +16,7 @@ def addMotorRecordToSelf(self, Id=None, name=None): class Pprm(Assembly): - def __init__(self, pvname, pvname_camera, name=None, in_target=1): + def __init__(self, pvname, pvname_camera, name=None, in_target=1, bs_channels={}): super().__init__(name=name) self.pvname = pvname self.in_target = in_target @@ -42,6 +43,14 @@ class Pprm(Assembly): self._append( AdjustablePvEnum, self.pvname + ":LED", name="led", is_setting=True ) + for bscn,bscc in bs_channels.items(): + self._append( + DetectorBsStream, + bscc, + name=bscn, + is_setting=False, + ) + def movein(self, target=None): if target == None: diff --git a/eco/xoptics/dcm_new.py b/eco/xoptics/dcm_new.py index f6f76b4..36df4d5 100644 --- a/eco/xoptics/dcm_new.py +++ b/eco/xoptics/dcm_new.py @@ -81,7 +81,7 @@ class DoubleCrystalMono(Assembly): self._append( AdjustablePv, energy_sp, - pvreadbackname=energy_rb, + # pvreadbackname=energy_rb, accuracy=0.5, name="energy", ) From 4815c71042d72c0bcfd5ee64d1ce7734e08fab62 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Sun, 10 Sep 2023 17:56:42 +0200 Subject: [PATCH 48/52] elog and fixes --- eco/__init__.py | 2 + eco/acquisition/daq_client.py | 18 +++- eco/bernina/bernina.py | 185 ++++++++++++++++++++++------------ eco/bernina/config.py | 25 ++--- eco/elements/adjustable.py | 94 +++++++++++++++-- eco/elements/assembly.py | 90 +++++++++++++++-- eco/elements/memory.py | 67 +++++++++--- eco/loptics/bernina_laser.py | 21 ++-- eco/utilities/config.py | 4 + eco/utilities/elog.py | 87 ++++++++++++++-- eco/utilities/elog_scilog.py | 55 +++++++--- 11 files changed, 501 insertions(+), 147 deletions(-) diff --git a/eco/__init__.py b/eco/__init__.py index 33e053b..0745050 100644 --- a/eco/__init__.py +++ b/eco/__init__.py @@ -4,3 +4,5 @@ except: print("cannot import Prototypic protocol classes") from eco.elements.assembly import Assembly + +ELOG = None diff --git a/eco/acquisition/daq_client.py b/eco/acquisition/daq_client.py index 37b459c..82474a8 100644 --- a/eco/acquisition/daq_client.py +++ b/eco/acquisition/daq_client.py @@ -1,6 +1,8 @@ import requests from pathlib import Path from time import sleep + +from eco.elements.protocols import Adjustable from ..epics.detector import DetectorPvDataStream from epics import PV from ..acquisition.utilities import Acquisition @@ -45,7 +47,7 @@ class Daq(Assembly): self.broker_address = broker_address self.broker_address_aux = broker_address_aux self.timeout = timeout - self.pgroup = pgroup + self._pgroup = pgroup if type(pulse_id_adj) is str: self.pulse_id = DetectorPvDataStream(pulse_id_adj, name="pulse_id") self._pid_wo_automonitor = PV( @@ -63,6 +65,20 @@ class Daq(Assembly): self.rate_multiplicator = rate_multiplicator + @property + def pgroup(self): + if isinstance(self._pgroup, Adjustable): + return self._pgroup.get_current_value() + else: + return self._pgroup + + @pgroup.setter + def pgroup(self, value): + if isinstance(self._pgroup, Adjustable): + self._pgroup.set_target_value(value).wait() + else: + self._pgroup = value + def acquire(self, file_name=None, Npulses=100, acq_pars={}): print(acq_pars) print(file_name, Npulses) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index b95b9b0..f375d4a 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -1,6 +1,7 @@ import json from pathlib import Path from threading import Thread +import eco from eco.acquisition.scan import NumpyEncoder from eco.devices_general.powersockets import MpodModule from eco.elements.adjustable import AdjustableFS @@ -35,7 +36,6 @@ namespace = Namespace( namespace.alias_namespace.data = [] # Adding stuff that might be relevant for stuff configured below (e.g. config) - _config_bernina_dict = AdjustableFS( "/sf/bernina/config/eco/configuration/bernina_config.json", name="_config_bernina_dict", @@ -44,6 +44,31 @@ from eco.elements.adj_obj import AdjustableObject namespace.append_obj(AdjustableObject, _config_bernina_dict, name="config_bernina") +namespace.append_obj( + "Elog", + "https://elog-gfa.psi.ch/Bernina", + screenshot_directory="/tmp", + name="elog_gfa", + module_name="eco.utilities.elog", +) + +namespace.append_obj( + "Elog", + pgroup_adj=config_bernina.pgroup, + name="scilog", + module_name="eco.utilities.elog_scilog", +) + +namespace.append_obj( + "ElogsMultiplexer", + scilog, + elog_gfa, + name="elog", + module_name="eco.utilities.elog", +) + +eco.ELOG = elog + namespace.append_obj( "DummyAdjustable", module_name="eco.elements.adjustable", @@ -854,23 +879,23 @@ namespace.append_obj( ) namespace.append_obj( - "MpodModule", - "SARES21-CPCL-PS7071", - [1,2,3,4], - ['ch1','ch2','ch3','ch4'], - module_string='LV_OMPV_1', - name="power_LV_patch1", - module_name="eco.devices_general.powersockets", + "MpodModule", + "SARES21-CPCL-PS7071", + [1, 2, 3, 4], + ["ch1", "ch2", "ch3", "ch4"], + module_string="LV_OMPV_1", + name="power_LV_patch1", + module_name="eco.devices_general.powersockets", ) namespace.append_obj( - "MpodModule", - "SARES21-CPCL-PS7071", - [5,6,7,8], - ['ch1','ch2','ch3','ch4'], - module_string='LV_OMPV_1', - name="power_LV_patch2", - module_name="eco.devices_general.powersockets", + "MpodModule", + "SARES21-CPCL-PS7071", + [5, 6, 7, 8], + ["ch1", "ch2", "ch3", "ch4"], + module_string="LV_OMPV_1", + name="power_LV_patch2", + module_name="eco.devices_general.powersockets", ) # @@ -936,7 +961,7 @@ namespace.append_obj( namespace.append_obj( "Daq", instrument="bernina", - pgroup=config_bernina.pgroup(), + pgroup=config_bernina.pgroup, channels_JF=channels_JF, channels_BS=channels_BS, channels_BSCAM=channels_BSCAM, @@ -1365,15 +1390,25 @@ def _create_metadata_structure_start_scan( except: print("Count not retrieve ipython scan command!") - message_string = f'Acquisition run {runno}: {metadata["name"]}\n' + message_string = f"#### Run {runno}" + if metadata["name"]: + message_string += f': {metadata["name"]}\n' + else: + message_string += "\n" + if "scan_command" in metadata.keys(): - message_string += metadata["scan_command"] + "\n" - message_string += metadata["scan_info_file"] + "\n" - scan._elog_id = elog.post( - message_string, Title=f'Run {runno}: {metadata["name"]}' + message_string += "`" + metadata["scan_command"] + "`\n" + message_string += "`" + metadata["scan_info_file"] + "`\n" + elog_ids = elog.post( + message_string, + Title=f'Run {runno}: {metadata["name"]}', + text_encoding="markdown", ) + scan._elog_id = elog_ids[1] metadata.update({"elog_message_id": scan._elog_id}) - metadata.update({"elog_post_link": scan._elog._log._url + str(scan._elog_id)}) + metadata.update( + {"elog_post_link": scan._elog[1]._log._url + str(scan._elog_id)} + ) except: print("elog posting failed") if not append_status_info: @@ -1685,40 +1720,40 @@ class N2jet(Assembly): class Incoupling(Assembly): def __init__(self, name=None): super().__init__(name=name) - self._append(SmaractRecord, "SARES23:ESB10", name="ver", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB13", name="hor", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB11", name="x", is_setting=True) - self._append( - MotorRecord, - "SLAAR21-LMOT-M521:MOTOR_1", - name="delaystage_eos", - is_setting=True, - ) - self._append( - DelayTime, - self.delaystage_eos, - name="delay_eos", - is_setting=False, - is_display=True, - ) - self._append( - AdjustablePvEnum, - "SLAAR21-LDIO-LAS6991:SET_BO02", - name="eos_is_shut", - is_setting=True, - ) - self._append( - DigitizerIoxosBoxcarChannel, - "SARES20-LSCP9-FNS:CH1", - name=f"signal_pol0", - is_setting=True, - ) - self._append( - DigitizerIoxosBoxcarChannel, - "SARES20-LSCP9-FNS:CH3", - name=f"signal_pol1", - is_setting=True, - ) + self._append(SmaractRecord, "SARES23:ESB12", name="ver", is_setting=True) + self._append(SmaractRecord, "SARES23:ESB11", name="hor", is_setting=True) + # self._append(SmaractRecord, "SARES23:ESB11", name="x", is_setting=True) + # self._append( + # MotorRecord, + # "SLAAR21-LMOT-M521:MOTOR_1", + # name="delaystage_eos", + # is_setting=True, + # ) + # self._append( + # DelayTime, + # self.delaystage_eos, + # name="delay_eos", + # is_setting=False, + # is_display=True, + # ) + # self._append( + # AdjustablePvEnum, + # "SLAAR21-LDIO-LAS6991:SET_BO02", + # name="eos_is_shut", + # is_setting=True, + # ) + # self._append( + # DigitizerIoxosBoxcarChannel, + # "SARES20-LSCP9-FNS:CH1", + # name=f"signal_pol0", + # is_setting=True, + # ) + # self._append( + # DigitizerIoxosBoxcarChannel, + # "SARES20-LSCP9-FNS:CH3", + # name=f"signal_pol1", + # is_setting=True, + # ) namespace.append_obj( @@ -1728,8 +1763,6 @@ namespace.append_obj( ) - - # namespace.append_obj( # "High_field_thz_chamber", # name="thc", @@ -2373,12 +2406,20 @@ namespace.append_obj( ## N2 sample heater setup from eco.devices_general.env_sensors import WagoSensor + + class SampleHeaterJet(Assembly): - def __init__(self,name='sampleheaterjet'): + def __init__(self, name="sampleheaterjet"): super().__init__(name=name) - self._append(WagoSensor,pvbase='SARES20-CWAG-GPS01:TEMP-T9', name='sensor_sample') - self._append(WagoSensor,pvbase='SARES20-CWAG-GPS01:TEMP-T10', name='sensor_jet_mount') - self._append(WagoSensor,pvbase='SARES20-CWAG-GPS01:TEMP-T11', name='sensor_hexapod') + self._append( + WagoSensor, pvbase="SARES20-CWAG-GPS01:TEMP-T9", name="sensor_sample" + ) + self._append( + WagoSensor, pvbase="SARES20-CWAG-GPS01:TEMP-T10", name="sensor_jet_mount" + ) + self._append( + WagoSensor, pvbase="SARES20-CWAG-GPS01:TEMP-T11", name="sensor_hexapod" + ) namespace.append_obj(SampleHeaterJet, name="heater_jet", lazy=True) @@ -2386,18 +2427,28 @@ namespace.append_obj(SampleHeaterJet, name="heater_jet", lazy=True) ## sample illumination from eco.devices_general.powersockets import MpodChannel + + class IlluminatorsLasers(Assembly): - def __init__(self,name='sample_illumination'): + def __init__(self, name="sample_illumination"): super().__init__(name=name) - self._append(MpodChannel,pvbase='SARES21-CPCL-PS7071', channel_number=2, name='illumination_1') - self._append(MpodChannel,pvbase='SARES21-CPCL-PS7071', channel_number=2, name='flattening_laser') + self._append( + MpodChannel, + pvbase="SARES21-CPCL-PS7071", + channel_number=2, + name="illumination_1", + ) + self._append( + MpodChannel, + pvbase="SARES21-CPCL-PS7071", + channel_number=2, + name="flattening_laser", + ) namespace.append_obj(IlluminatorsLasers, name="sample_illumination", lazy=True) - - ## LIQUID jet setup # from eco.devices_general.wago import AnalogOutput diff --git a/eco/bernina/config.py b/eco/bernina/config.py index d72d544..4a6eacf 100755 --- a/eco/bernina/config.py +++ b/eco/bernina/config.py @@ -32,20 +32,12 @@ components = [ "kwargs": {}, "lazy": True, }, - { - "name": "elog", - "type": "eco.utilities.elog:Elog", - "args": ["https://elog-gfa.psi.ch/Bernina"], - "kwargs": { - "screenshot_directory": "/tmp", - }, - }, - { - "name": "screenshot", - "type": "eco.utilities.elog:Screenshot", - "args": [], - "kwargs": {"screenshot_directory": "/sf/bernina/config/screenshots"}, - }, + # { + # "name": "screenshot", + # "type": "eco.utilities.elog:Screenshot", + # "args": [], + # "kwargs": {"screenshot_directory": "/sf/bernina/config/screenshots"}, + # }, # { # "name": "fel", # "type": "eco.fel.swissfel:SwissFel", @@ -406,7 +398,7 @@ components = [ # "default_file_path": None, # }, # }, - #{ + # { # "args": [ # config["checker_PV"], # config["checker_thresholds"], @@ -416,7 +408,7 @@ components = [ # "desc": "checker functions for data acquisition", # "type": "eco.acquisition.checkers:CheckerCA", # "kwargs": {}, - #}, + # }, # { # "args": [ # "SARES20-LSCP9-FNS:CH1:VAL_GET", @@ -481,7 +473,6 @@ components = [ "default_file_path": f"/sf/bernina/data/{config['pgroup']}/res/%s", }, }, - # { # "args": ["SARES23-"], # "name": "slit_kb", diff --git a/eco/elements/adjustable.py b/eco/elements/adjustable.py index b8bade4..68019a7 100644 --- a/eco/elements/adjustable.py +++ b/eco/elements/adjustable.py @@ -8,6 +8,7 @@ import itertools import colorama import numpy as np +import eco from eco.aliases import Alias from eco.devices_general.utilities import Changer @@ -105,6 +106,60 @@ def spec_convenience(Adj): Adj.mv = mv Adj.mvr = mvr + def wm_elog(self, premessage=None, tags=[]): + elog = self._get_elog() + tname = self.alias.get_full_name() + value = self.get_current_value() + + if premessage: + messages = [ + premessage, + f"{tname} is at {value}.", + ] + else: + messages = [f"{tname} is at {value}."] + self.mvr(value) + elog.post(*messages, tags=tags) + + def mv_elog(self, value, premessage=None, tags=[]): + elog = self._get_elog() + tname = self.alias.get_full_name() + start = self.get_current_value() + end = value + rel_change = end - start + if premessage: + messages = [ + premessage, + f"Changing {tname} from {start} by {rel_change} to {end}.", + ] + else: + messages = [f"Changing {tname} from {start} by {rel_change} to {end}."] + self.mv(value) + elog.post(*messages, tags=tags) + + def mvr_elog(self, value, premessage=None, tags=[]): + elog = self._get_elog() + tname = self.alias.get_full_name() + start = self.get_current_value() + end = start + value + rel_change = value + if premessage: + messages = [ + premessage, + f"Changing {tname} from {start} by {rel_change} to {end}.", + ] + else: + messages = [f"Changing {tname} from {start} by {rel_change} to {end}."] + self.mvr(value) + elog.post(*messages, tags=tags) + + if hasattr(Adj, "wm"): + Adj.wm_elog = wm_elog + if hasattr(Adj, "mv"): + Adj.mv_elog = mv_elog + if hasattr(Adj, "mvr"): + Adj.mvr_elog = mvr_elog + def call(self, value=None): if not value is None: return self.mv(value) @@ -113,6 +168,18 @@ def spec_convenience(Adj): Adj.__call__ = call + def _get_elog(self): + if hasattr(self, "_elog") and self._elog: + return self._elog + elif hasattr(self, "__elog") and self.__elog: + return self.__elog + elif eco.ELOG: + return eco.ELOG + else: + return None + + Adj._get_elog = _get_elog + return Adj @@ -304,12 +371,13 @@ def value_property(Adj, wait_for_change=True, value_name="_value"): @tweak_option @value_property class DummyAdjustable: - def __init__(self, name="no_adjustable", limits=[-100,100]): + def __init__(self, name="no_adjustable", limits=[-100, 100]): self.name = name self.alias = Alias(name) self.current_value = 0 self.limits = tuple(limits) + def get_current_value(self): return self.current_value @@ -320,12 +388,12 @@ class DummyAdjustable: return Changer( target=value, parent=self, changer=changer, hold=hold, stopper=None ) - + def get_limits(self): return self.limits - - def set_limits(self, lowlim,highlim): - self.limits = (lowlim,highlim) + + def set_limits(self, lowlim, highlim): + self.limits = (lowlim, highlim) def __repr__(self): name = self.name @@ -514,7 +582,6 @@ class AdjustableVirtual: for tc in self._active_changers: tc.wait() else: - for val, adj in zip(vals, self._adjustables): if val is not None: self._active_changers = [adj.set_target_value(val, hold=False)] @@ -558,7 +625,15 @@ class AdjustableVirtual: @tweak_option @value_property class AdjustableGetSet: - def __init__(self, foo_get, foo_set, precision=0, check_interval=None, cache_get_seconds=None, name=None): + def __init__( + self, + foo_get, + foo_set, + precision=0, + check_interval=None, + cache_get_seconds=None, + name=None, + ): """assumes a waiting setterin function, in case no check_interval parameter is supplied""" self.alias = Alias(name) self.name = name @@ -587,7 +662,7 @@ class AdjustableGetSet: def get_current_value(self): ts = time.time() - if self._cache_get_seconds and hasattr(self,'_get_cache'): + if self._cache_get_seconds and hasattr(self, "_get_cache"): if ts - self._get_cache[0] < self._cache_get_seconds: value = self._get_cache[1] else: @@ -595,11 +670,10 @@ class AdjustableGetSet: else: value = self._get() if self._cache_get_seconds: - self._get_cache= (ts,value) + self._get_cache = (ts, value) return value - @spec_convenience class AdjustableEnum: def __init__(self, adjustable_instance, enum_strs_ordered, name=None): diff --git a/eco/elements/assembly.py b/eco/elements/assembly.py index de5949b..48aa268 100644 --- a/eco/elements/assembly.py +++ b/eco/elements/assembly.py @@ -1,7 +1,14 @@ +from datetime import datetime +from inspect import isclass +import json +from pathlib import Path from tkinter import W +from markdown import markdown from numpy import isin +# from eco.acquisition.scan import NumpyEncoder + from eco.elements.protocols import Detector, InitialisationWaitable from ..aliases import Alias from tabulate import tabulate @@ -13,6 +20,8 @@ import subprocess from rich.progress import track from eco import Adjustable, Detector +import eco + _initializing_assemblies = [] @@ -63,7 +72,7 @@ class Collection: class Assembly: - def __init__(self, name=None, parent=None, is_alias=True): + def __init__(self, name=None, parent=None, is_alias=True, elog=None): self.name = name self.alias = Alias(name, parent=parent) # self.settings = [] @@ -74,6 +83,10 @@ class Assembly: self.view_toplevel_only = [] if memory.global_memory_dir: self.memory = memory.Memory(self) + if elog: + self.__elog = elog + else: + self.__class__.__elog = property(lambda dum: ELOG) def _append( self, @@ -86,9 +99,16 @@ class Assembly: is_alias=True, view_toplevel_only=True, call_obj=True, + append_property_with_name=False, **kwargs, ): - if call_obj and callable(foo_obj_init): + if isinstance(foo_obj_init, Adjustable) and not isclass(foo_obj_init): + self.__dict__[name] = foo_obj_init + elif isinstance(foo_obj_init, Detector) and not isclass(foo_obj_init): + self.__dict__[name] = foo_obj_init + elif isinstance(foo_obj_init, Assembly) and not isclass(foo_obj_init): + self.__dict__[name] = foo_obj_init + elif call_obj and callable(foo_obj_init): self.__dict__[name] = foo_obj_init(*args, **kwargs, name=name) else: self.__dict__[name] = foo_obj_init @@ -96,6 +116,17 @@ class Assembly: # except: # print(f'object {name} / {foo_obj_init} not initialized with name/parent') # self.__dict__[name] = foo_obj_init(*args, **kwargs) + if append_property_with_name: + if isinstance(self.__dict__[name], Adjustable): + self.__class__.__dict__[append_property_with_name] = property( + self.__dict__[name].get_current_value, + lambda val: self.__dict__[name].set_target_value(val).wait(), + ) + elif isinstance(self.__dict__[name], Detector): + self.__class__.__dict__[append_property_with_name] = property( + self.__dict__[name].get_current_value, + ) + if is_setting == "auto": is_setting = isinstance(self.__dict__[name], Adjustable) if is_setting: @@ -273,7 +304,7 @@ class Assembly: s = tabulate([[name, value] for name, value in stat_filt[stat_field].items()]) return s - def get_display_str(self): + def get_display_str(self, tablefmt="simple"): main_name = self.name stats = self.display_collection() # stats_dict = {} @@ -310,9 +341,47 @@ class Assembly: tab.append( [".".join([main_name, name]), value, unit, typechar, description] ) - s = tabulate(tab) + s = tabulate(tab, tablefmt=tablefmt) return s + def status_to_elog( + self, + text="", + text_encoding="markdown", + auto_title=True, + attach_display=True, + attach_status_file=True, + ): + elog = self._get_elog() + message = "" + files = [] + if auto_title: + message += markdown(f"#### Status {self.alias.get_full_name()}") + + if text: + if text_encoding == "markdown": + message += markdown(text) + if attach_display: + message += self.get_display_str(tablefmt="html") + + if attach_status_file: + stat = self.get_status() + tmppath = Path("/tmp") + filepath = tmppath / Path( + f"status_{self.alias.get_full_name}_{datetime.now().isoformat()}.json" + ) + with open(filepath, "w") as f: + # json.dump(stat, f, cls=NumpyEncoder, indent=4) + json.dump(stat, f, indent=4) + files.append(filepath) + + elog.post( + message, + *files, + text_encoding="html", + ) + # tags=[], + def __repr__(self): label = self.alias.get_full_name() + " status\n" return label + self.get_display_str() @@ -331,11 +400,10 @@ class Assembly: if isinstance(item, Assembly) and (item in _initializing_assemblies): continue if isinstance(item, InitialisationWaitable): - if isinstance(item,Assembly): + if isinstance(item, Assembly): _initializing_assemblies.append(item) item._wait_for_initialisation() - def _run_cmd(self, line, silent=True): if silent: print(f"Starting following commandline silently:\n" + line) @@ -346,6 +414,16 @@ class Assembly: else: subprocess.Popen(line, shell=True) + def _get_elog(self): + if hasattr(self, "_elog") and self._elog: + return self._elog + elif hasattr(self, "__elog") and self.__elog: + return self.__elog + elif eco.ELOG: + return eco.ELOG + else: + return None + import epics.pv import time diff --git a/eco/elements/memory.py b/eco/elements/memory.py index af02ccb..f79fbd3 100644 --- a/eco/elements/memory.py +++ b/eco/elements/memory.py @@ -5,6 +5,10 @@ from ..utilities.keypress import KeyPress from tabulate import tabulate import sys, colorama from inspect import getargspec +import eco +from ansi2html import Ansi2HTMLConverter + +conv = Ansi2HTMLConverter() global_memory_dir = None @@ -60,8 +64,23 @@ class Memory: # print(self.get_memory_difference_str(index)) self.recall(memory_index=index) + def _get_elog(self): + if hasattr(self, "_elog") and self._elog: + return self._elog + elif hasattr(self, "__elog") and self.__elog: + return self.__elog + elif eco.ELOG: + return eco.ELOG + else: + return None + def memorize( - self, message=None, attributes={}, force_message=True, preset_varname=None + self, + message=None, + attributes={}, + force_message=True, + preset_varname=None, + to_elog=True, ): self.setup_path() stat_now = self.obj_parent.get_status(base=self.obj_parent) @@ -86,6 +105,13 @@ class Memory: self._memories(mem) print(f"Saved memory for {self.obj_parent.alias.get_full_name()}: {message}") print(f"memory file: {tmp.file_path.as_posix()}") + if to_elog: + elog = self._get_elog() + elog.post( + f"Saved memory for {self.obj_parent.alias.get_full_name()}: {message}", + tmp.file_path, + text_encoding="markdown", + ) def get_memory(self, input_obj=None, index=None, key=None, filter_existing=True): if not input_obj is None: @@ -202,7 +228,12 @@ class Memory: ... def get_memory_difference_str( - self, memory, select=None, ask_select=True, show_changes_only=False + self, + memory, + select=None, + ask_select=True, + show_changes_only=False, + tablefmt="plain", ): # mem = self.get_memory(index=memory_index) mem = memory @@ -218,12 +249,15 @@ class Memory: tselstr = " " if present_value == recall_value: changed = False - comp_indicator = ( - colorama.Fore.GREEN - + colorama.Style.BRIGHT - + "==" - + colorama.Style.RESET_ALL - ) + if tablefmt == "html": + comp_indicator = "==" + else: + comp_indicator = ( + colorama.Fore.GREEN + + colorama.Style.BRIGHT + + "==" + + colorama.Style.RESET_ALL + ) else: changed = True if not tsel: @@ -233,14 +267,18 @@ class Memory: tdiff = f"{recall_value - present_value:+g}" except TypeError: tdiff = "special" - comp_indicator = ( - colorama.Fore.RED - + colorama.Style.BRIGHT - + f"{tdiff:s}" - + colorama.Style.RESET_ALL - ) + if tablefmt == "html": + comp_indicator = f"{tdiff:s}" + else: + comp_indicator = ( + colorama.Fore.RED + + colorama.Style.BRIGHT + + f"{tdiff:s}" + + colorama.Style.RESET_ALL + ) if show_changes_only and (not changed): continue + table.append([n, tselstr, key, present_value, comp_indicator, recall_value]) if len(table) == 0: @@ -256,6 +294,7 @@ class Memory: "memory", ], colalign=("decimal", "center", "left", "decimal", "center", "decimal"), + tablefmt=tablefmt, ) def select_from_memory( diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index 7e560a6..a25f960 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -157,11 +157,12 @@ class FilterWheelAttenuator(Assembly): self.wheel_1.home() self.wheel_2.home() + class Stage_LXT_Delay(AdjustableVirtual): def __init__(self, fine_delay_adj, coarse_delay_adj, direction=1, name=None): self._fine_delay_adj = fine_delay_adj self._coarse_delay_adj = coarse_delay_adj - self._direction=direction + self._direction = direction self.switch_threshold = AdjustableFS( f"/photonics/home/gac-bernina/eco/configuration/{name}_combined_delay_phase_shifter_threshold", name="switch_threshold", @@ -170,15 +171,14 @@ class Stage_LXT_Delay(AdjustableVirtual): self.offset_fine_adj = AdjustableFS( f"/photonics/home/gac-bernina/eco/configuration/{name}_conbined_fine_adj_offset", name="offset_fine_adj", - default_value=0., + default_value=0.0, ) self.offset_coarse_adj = AdjustableFS( f"/photonics/home/gac-bernina/eco/configuration/{name}_combined_coarse_adj_offset", name="offset_coarse_adj", - default_value=0., + default_value=0.0, ) - AdjustableVirtual.__init__( self, [self._fine_delay_adj, self._coarse_delay_adj], @@ -191,8 +191,8 @@ class Stage_LXT_Delay(AdjustableVirtual): def _get_comb_delay(self, pd, ps): ps_rel = ps - self.offset_coarse_adj() pd_rel = pd - self.offset_fine_adj() - return (ps_rel + pd_rel)*self._direction - + return (ps_rel + pd_rel) * self._direction + def _set_comb_delay(self, delay): if delay < abs(self.switch_threshold()): ### check to prevent slow phaseshifter corrections <50fs @@ -204,7 +204,7 @@ class Stage_LXT_Delay(AdjustableVirtual): else: ps_pos = self.offset_coarse_adj() + delay pd_pos = self.offset_fine_adj() - return self._direction*pd_pos, self._direction*ps_pos + return self._direction * pd_pos, self._direction * ps_pos class LaserBernina(Assembly): @@ -235,8 +235,6 @@ class LaserBernina(Assembly): MotorRecord, self.pvname + "-M534:MOT", name="wp_att", is_setting=True ) - - self._append( AdjustableFS, "/photonics/home/gac-bernina/eco/configuration/wp_att_calibration", @@ -285,7 +283,9 @@ class LaserBernina(Assembly): # self._append( # DelayTime, self.delaystage_pump, name="delay_pump", is_setting=True # ) - self._append(LaserRateControl, name="rate", is_setting=True, is_display="recursive") + self._append( + LaserRateControl, name="rate", is_setting=True, is_display="recursive" + ) self._append(XltEpics, name="xlt", is_setting=True, is_display="recursive") # Upstairs, Laser 1 LAM # self._append( @@ -321,7 +321,6 @@ class LaserBernina(Assembly): # ) - class DelayTime(AdjustableVirtual): def __init__( self, stage, direction=1, passes=2, reset_current_value_to=True, name=None diff --git a/eco/utilities/config.py b/eco/utilities/config.py index 28b42a7..ebcc6d5 100644 --- a/eco/utilities/config.py +++ b/eco/utilities/config.py @@ -273,6 +273,10 @@ class Namespace(Assembly): self.root_module = root_module self.alias_namespace = alias_namespace + @property + def initialisation_times_sorted(self): + return dict(sorted(self.initialisation_times.items(), key=lambda w: w[1])) + @property def initialized_names(self): return set(self.initialized_items.keys()) diff --git a/eco/utilities/elog.py b/eco/utilities/elog.py index 92a56b0..8324481 100755 --- a/eco/utilities/elog.py +++ b/eco/utilities/elog.py @@ -1,12 +1,29 @@ +from pathlib import Path import elog as _elog_ha from getpass import getuser as _getuser from getpass import getpass as _getpass import os, datetime, subprocess +from markdown import markdown import urllib3 urllib3.disable_warnings() +###################### +class ElogsMultiplexer: + def __init__(self, *args): + self.elogs = args + + def post(self, *args, **kwargs): + mids = [] + for elog in self.elogs: + mids.append(elog.post(*args, **kwargs)) + return mids + + +########################## + + def getDefaultElogInstance(url, **kwargs): from pathlib import Path @@ -32,17 +49,74 @@ class Elog: self._screenshot = Screenshot(screenshot_directory) self.read = self._log.read - def post(self, *args, Title=None, Author=None, Encoding="html", **kwargs): + def post( + self, + *args, + text_encoding="markdown", + markdown_extensions=["fenced_code"], + tags=[], + Title=None, + Author=None, + **kwargs, + ): """ """ - if Encoding == "html": - args = list(args) - args[0] = args[0].replace("\n", "
\n") + + message = "" + file_paths = [] + + for targ in args: + if not (isinstance(targ, str) or isinstance(targ, Path)): + raise Exception( + "Log messages should be of type string or pathlib.Path!" + ) + + if isinstance(targ, Path): + if Path(targ).expanduser().exists(): + print("file exists") + file_paths.append(targ.as_posix()) + if targ.suffix[1:] in ["jpg", "png"]: + if text_encoding in ["markdown", "html"]: + message += f'

' + else: + targ = str(targ) + if text_encoding == "markdown": + message += markdown(targ, extensions=markdown_extensions) + Encoding = "html" + elif text_encoding == "html": + Encoding = "html" + else: + message += targ + "\n" + Encoding = "plain" + if not Author: Author = self.user - return self._log.post( - *args, Title=Title, Author=Author, Encoding=Encoding, **kwargs + + if file_paths: + attachments = file_paths + else: + attachments = None + mid = self._log.post( + message, + attachments=attachments, + Title=Title, + Author=Author, + Encoding=Encoding, + **kwargs, ) + if file_paths: + pm, patt, pa = self._log.read(mid) + for ntpa, tpa in enumerate(pa): + filename = "".join(Path(tpa).parts[-1].split("_")[2:]) + print(filename) + Nocc = pm.count(f"temporarypath-attachment_{ntpa}") + print(Nocc) + if Nocc: + pm = pm.replace(f"temporarypath-attachment_{ntpa}", tpa) + self._log.post(pm, msg_id=mid) + + return mid + def screenshot(self, message="", window=False, desktop=False, delay=3, **kwargs): filepath = self._screenshot.shoot()[0] kwargs.update({"attachments": [filepath]}) @@ -58,7 +132,6 @@ class Screenshot: self.user = kwargs["user"] def show_directory(self): - p = subprocess.Popen( ["nautilus", self._screenshot_directory], stdout=subprocess.PIPE, diff --git a/eco/utilities/elog_scilog.py b/eco/utilities/elog_scilog.py index 6191b33..4c01069 100755 --- a/eco/utilities/elog_scilog.py +++ b/eco/utilities/elog_scilog.py @@ -1,3 +1,4 @@ +from functools import lru_cache from markdown import markdown from scilog import SciLog, LogbookMessage from getpass import getuser as _getuser @@ -6,6 +7,8 @@ import os, datetime, subprocess import urllib3 from pathlib import Path +from eco.elements.assembly import Assembly + urllib3.disable_warnings() @@ -28,7 +31,6 @@ def getDefaultElogInstance( _pw = _getpass() kwargs.update(dict(password=_pw)) log = SciLog(url, options := {"username": user, "password": kwargs["password"]}) - print(options) if pgroup: lbs = log.get_logbooks(ownerGroup=pgroup) if len(lbs) > 1: @@ -37,37 +39,62 @@ def getDefaultElogInstance( return log, user -class Elog: +class Elog(Assembly): def __init__( self, url="https://scilog.psi.ch/api/v1", - pgroup=None, + pgroup_adj=None, screenshot_directory="", + name="scilog", **kwargs, ): - self._log, self.user = getDefaultElogInstance(url, pgroup=pgroup, **kwargs) + super().__init__(name=name) + self.scilog_url = url + self._append(pgroup_adj, name="pgroup") + dummy, self.user = getDefaultElogInstance( + url, pgroup=pgroup_adj.get_current_value(), **kwargs + ) + self.__class__._log = property( + lambda dum: self._get_scilog_dynamically( + self.scilog_url, self.pgroup.get_current_value() + ) + ) self._screenshot = Screenshot(screenshot_directory) # self.read = self._log.read - def post(self, *args, tags=[], text_encoding="markdown", **kwargs): - """ """ + @lru_cache + def _get_scilog_dynamically(self, url, pgroup): + log, user = getDefaultElogInstance(url, pgroup=pgroup) + self.user = user + return log + + def post( + self, + *args, + tags=[], + text_encoding="markdown", + markdown_extensions=["fenced_code"], + **kwargs, + ): + """args can be text or pathlibPath instances (for files to be uploaded)""" msg = LogbookMessage() for targ in args: - if not ((type(targ) is str) or isinstance(targ, Path)): + if not (isinstance(targ, str) or isinstance(targ, Path)): raise Exception("Log messages should be of type string!") - try: - print("trying file") + if isinstance(targ, Path): if Path(targ).expanduser().exists(): print("file exists") - msg.add_file(targ) - except: - print("this is text") + msg.add_file(targ.as_posix()) + else: + targ = str(targ) if text_encoding == "markdown": - print("markdown warning") - msg.add_text(markdown(targ)) + msg.add_text(markdown(targ, extensions=markdown_extensions)) + elif text_encoding == "html": + msg.add_text(targ) else: msg.add_text(targ) + for tag in tags: msg.add_tag(tag) From b619a83ddad215f10daf00a2278ac3e92b207bef Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Sun, 10 Sep 2023 18:18:22 +0200 Subject: [PATCH 49/52] lxt Assemblification --- eco/bernina/bernina.py | 13 +++++++- eco/loptics/bernina_laser.py | 65 ++++++++++++++++++++++++++++++++++++ eco/utilities/elog_scilog.py | 2 +- 3 files changed, 78 insertions(+), 2 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index f375d4a..e5f5987 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -2252,8 +2252,19 @@ class Laser_Xray_Timing(Assembly): namespace.append_obj( Laser_Xray_Timing, lazy=True, - name="lxt", + name="lxt_01", ) + +namespace.append_obj( + "StageLxtDelay", + las.delay_glob, + las.xlt, + lazy=True, + name="lxt", + direction=-1, + module_name="eco.loptics.bernina_laser", +) + ##combined delaystage with phase shifter motion## diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index a25f960..2e4326e 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -158,6 +158,71 @@ class FilterWheelAttenuator(Assembly): self.wheel_2.home() +class StageLxtDelay(Assembly): + def __init__(self, fine_delay_adj, coarse_delay_adj, direction=1, name=None): + super().__init__(name=name) + self._append(fine_delay_adj, name="_fine_delay_adj", is_setting=True) + self._append(coarse_delay_adj, name="_coarse_delay_adj", is_setting=True) + self._append(AdjustableMemory, direction, name="_direction", is_setting=True) + self._append( + AdjustableFS, + f"/photonics/home/gac-bernina/eco/configuration/{name}_combined_delay_phase_shifter_threshold", + name="switch_threshold", + default_value=50e-12, + is_setting=True, + ) + self._append( + AdjustableFS, + f"/photonics/home/gac-bernina/eco/configuration/{name}_conbined_fine_adj_offset", + name="offset_fine_adj", + default_value=0.0, + is_setting=True, + ) + self._append( + AdjustableFS, + f"/photonics/home/gac-bernina/eco/configuration/{name}_combined_coarse_adj_offset", + name="offset_coarse_adj", + default_value=0.0, + is_setting=True, + ) + + self._append( + AdjustableVirtual, + [self._fine_delay_adj, self._coarse_delay_adj], + self._get_comb_delay, + self._set_comb_delay, + name="delay", + unit="s", + ) + + def _get_comb_delay(self, pd, ps): + ps_rel = ps - self.offset_coarse_adj() + pd_rel = pd - self.offset_fine_adj() + return (ps_rel + pd_rel) * self._direction.get_current_value() + + def _set_comb_delay(self, delay): + if delay < abs(self.switch_threshold.get_current_value()): + ### check to prevent slow phaseshifter corrections <50fs + if ( + np.abs( + self._coarse_delay_adj.get_current_value() + - self.offset_coarse_adj.get_current_value() + ) + > 50e-15 + ): + ps_pos = self.offset_coarse_adj.get_current_value() + else: + ps_pos = None + pd_pos = self.offset_fine_adj.get_current_value() + delay + else: + ps_pos = self.offset_coarse_adj.get_current_value() + delay + pd_pos = self.offset_fine_adj.get_current_value() + return ( + self._direction.get_current_value() * pd_pos, + self._direction.get_current_value() * ps_pos, + ) + + class Stage_LXT_Delay(AdjustableVirtual): def __init__(self, fine_delay_adj, coarse_delay_adj, direction=1, name=None): self._fine_delay_adj = fine_delay_adj diff --git a/eco/utilities/elog_scilog.py b/eco/utilities/elog_scilog.py index 4c01069..e45ab4b 100755 --- a/eco/utilities/elog_scilog.py +++ b/eco/utilities/elog_scilog.py @@ -98,7 +98,7 @@ class Elog(Assembly): for tag in tags: msg.add_tag(tag) - self._log.send_logbook_message(msg) + return self._log.send_logbook_message(msg) def screenshot(self, message="", window=False, desktop=False, delay=3, **kwargs): filepath = self._screenshot.shoot()[0] From 4d6c9edb7a7daa2423f4a7da490c33b93cf2f055 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Tue, 12 Sep 2023 11:18:21 +0200 Subject: [PATCH 50/52] added ps cahnnels to pprm and fix in run table --- eco/bernina/bernina.py | 5 +++++ eco/devices_general/powersockets.py | 2 +- eco/utilities/runtable.py | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index e5f5987..bdf34ab 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -427,6 +427,11 @@ namespace.append_obj( "Pprm", "SAROP21-PPRM113", "SAROP21-PPRM113", + bs_channels={ + "intensity": "SAROP21-PPRM113:intensity", + "xpos": "SAROP21-PPRM113:x_fit_mean", + "ypos": "SAROP21-PPRM113:y_fit_mean", + }, module_name="eco.xdiagnostics.profile_monitors", name="prof_mono", in_target=3, diff --git a/eco/devices_general/powersockets.py b/eco/devices_general/powersockets.py index a4ebeb5..cb318e5 100644 --- a/eco/devices_general/powersockets.py +++ b/eco/devices_general/powersockets.py @@ -131,4 +131,4 @@ class MpodModule(Assembly): def __init__(self,pvbase,channelnumbers, channelnames, module_string='LV_OMPV_1', name=None): super().__init__(name=name) for channelnumber,channelname in zip(channelnumbers,channelnames): - self._append(MpodChannel,pvbase,channel_number=channelnumber, module_string=module_string,name=channelname) \ No newline at end of file + self._append(MpodChannel,pvbase,channel_number=channelnumber, module_string=module_string,name=channelname) diff --git a/eco/utilities/runtable.py b/eco/utilities/runtable.py index 26ecac3..cbfe5f6 100644 --- a/eco/utilities/runtable.py +++ b/eco/utilities/runtable.py @@ -774,6 +774,11 @@ class Run_Table_DataFrame(DataFrame): good_dev_adj = {} bad_dev_adj = {} for name, adj in adjs.items(): + try: + adj.get_current_value() + except Exception as e: + print(f"get_current_value() method of {name} failed with {e}") + continue if check_for_current_none_values and (adj.get_current_value() is None): bad_dev_adj[name] = adj else: From 634e904a926e21b44548345a9179e5408740aa3f Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Sat, 16 Sep 2023 10:07:31 +0200 Subject: [PATCH 51/52] mono, fix etc --- eco/acquisition/checkers.py | 47 ++++++++++++++++ eco/acquisition/scan.py | 11 +++- eco/bernina/bernina.py | 64 ++++++++++++++------- eco/devices_general/motors.py | 9 +++ eco/loptics/bernina_laser.py | 14 +++-- eco/utilities/feedback.py | 49 ++++++++++++++++ eco/utilities/runtable.py | 4 -- eco/xoptics/dcm_new.py | 102 +++++++++++++++++++++++++++++++++- 8 files changed, 269 insertions(+), 31 deletions(-) create mode 100644 eco/utilities/feedback.py diff --git a/eco/acquisition/checkers.py b/eco/acquisition/checkers.py index 2551c95..8033706 100644 --- a/eco/acquisition/checkers.py +++ b/eco/acquisition/checkers.py @@ -3,6 +3,8 @@ import numpy as np from ..elements.adjustable import AdjustableFS from ..epics.adjustable import AdjustablePv from ..epics.detector import DetectorPvDataStream +from ..detector.detectors_psi import DetectorBsStream + from ..elements.assembly import Assembly @@ -51,6 +53,51 @@ class CheckerCA(Assembly): print(f" given limit was {self.required_fraction()*100}%.") return fraction >= self.required_fraction() +class CheckerBS(Assembly): + def __init__(self, bs_channel=None, thresholds=None, required_fraction=None, name=None): + super().__init__(name=name) + self._append(DetectorBsStream, bs_channel, name="monitor") + self._append( + AdjustableFS, + "/photonics/home/gac-bernina/eco/configuration/checker_thresholds", + default_value=sorted(thresholds), + name="thresholds", + ) + self._append( + AdjustableFS, + "/photonics/home/gac-bernina/eco/configuration/checker_required_fraction", + default_value=required_fraction, + name="required_fraction", + ) + + def check_now(self): + cv = self.monitor.get_current_value() + thresholds = self.thresholds() + if cv > thresholds[0] and cv < thresholds[1]: + return True + else: + return False + + # def append_to_data(self, **kwargs): + # self.data.append(kwargs["value"]) + + def clear_and_start_counting(self): + self.monitor.accumulate_start() + + # def stopcounting(self): + # self.PV.clear_callbacks() + + def stop_and_analyze(self): + data = np.asarray(self.monitor.accumulate_stop()) + thresholds = self.thresholds() + good = np.logical_and(data > thresholds[0], data < thresholds[1]) + fraction = good.sum() / len(good) + isgood = fraction >= self.required_fraction() + if not isgood: + print(f"Checker: {fraction*100}% inside limits {self.thresholds()},") + print(f" given limit was {self.required_fraction()*100}%.") + return fraction >= self.required_fraction() + # checker_obj = Checker_obj(checkerPV) diff --git a/eco/acquisition/scan.py b/eco/acquisition/scan.py index 350f9e0..f81844c 100755 --- a/eco/acquisition/scan.py +++ b/eco/acquisition/scan.py @@ -84,9 +84,17 @@ class Scan: self.nextStep = 0 self.basepath = basepath self.scan_info_dir = scan_info_dir + + anames = [] + for ta in adjustables: + try: + anames.append(ta.alias.get_full_name()) + except: + anames.append(ta.name) + self.scan_info = { "scan_parameters": { - "name": [ta.name for ta in adjustables], + "name": anames, "Id": [ta.Id if hasattr(ta, "Id") else "noId" for ta in adjustables], }, "scan_values_all": values, @@ -406,7 +414,6 @@ class Scans: return_at_end=True, **kwargs_callbacks, ): - adjustable = DummyAdjustable() positions = list(range(N_repetitions)) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index bdf34ab..c27f2e3 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -44,31 +44,37 @@ from eco.elements.adj_obj import AdjustableObject namespace.append_obj(AdjustableObject, _config_bernina_dict, name="config_bernina") +#namespace.append_obj( +# "Elog", +# "https://elog-gfa.psi.ch/Bernina", +# screenshot_directory="/tmp", +# name="elog_gfa", +# module_name="eco.utilities.elog", +#) + +#namespace.append_obj( +# "Elog", +# pgroup_adj=config_bernina.pgroup, +# name="scilog", +# module_name="eco.utilities.elog_scilog", +#) + +#namespace.append_obj( +# "ElogsMultiplexer", +# scilog, +# elog_gfa, +# name="elog", +# module_name="eco.utilities.elog", +#) namespace.append_obj( "Elog", "https://elog-gfa.psi.ch/Bernina", screenshot_directory="/tmp", - name="elog_gfa", - module_name="eco.utilities.elog", -) - -namespace.append_obj( - "Elog", - pgroup_adj=config_bernina.pgroup, - name="scilog", - module_name="eco.utilities.elog_scilog", -) - -namespace.append_obj( - "ElogsMultiplexer", - scilog, - elog_gfa, name="elog", module_name="eco.utilities.elog", ) eco.ELOG = elog - namespace.append_obj( "DummyAdjustable", module_name="eco.elements.adjustable", @@ -1418,7 +1424,6 @@ def _create_metadata_structure_start_scan( print("elog posting failed") if not append_status_info: return - t_start_rt = time.time() d = {} ## use values from status for run_table try: @@ -1427,6 +1432,7 @@ def _create_metadata_structure_start_scan( d.update(status["status"]) except: print("Tranferring values from status to run_table did not work") + t_start_rt = time.time() try: run_table.append_run(runno, metadata=metadata, d=d) except: @@ -1443,6 +1449,15 @@ namespace.append_obj( pvname="SLAAR21-LTIM01-EVR0:CALCI", thresholds=[0.2, 10], required_fraction=0.6, + name="checker_ioxos_old", +) + +namespace.append_obj( + "CheckerBS", + module_name="eco.acquisition.checkers", + bs_channel="SAROP21-PBPS133:INTENSITY", + thresholds=[0.2, 10], + required_fraction=0.6, name="checker", ) @@ -2262,7 +2277,7 @@ namespace.append_obj( namespace.append_obj( "StageLxtDelay", - las.delay_glob, + las.delay_pump, las.xlt, lazy=True, name="lxt", @@ -2457,13 +2472,24 @@ class IlluminatorsLasers(Assembly): self._append( MpodChannel, pvbase="SARES21-CPCL-PS7071", - channel_number=2, + channel_number=4, name="flattening_laser", ) namespace.append_obj(IlluminatorsLasers, name="sample_illumination", lazy=True) +## Timetool feedback +namespace.append_obj( + "Feedback_Timetool", + name="tt_kb_feedback", + pvname="SLAAR21-SPECTT:AT", + control_adj=dummy_adjustable, + lazy=True, + module_name="eco.utilities.feedback", +) + + ## LIQUID jet setup diff --git a/eco/devices_general/motors.py b/eco/devices_general/motors.py index 16f4a75..6aacd11 100755 --- a/eco/devices_general/motors.py +++ b/eco/devices_general/motors.py @@ -436,6 +436,7 @@ class MotorRecord(Assembly): is_psi_mforce=False, schneider_config=None, expect_bad_limits=True, + has_park_pv=False, ): super().__init__(name=name) # self.settings.append(self) @@ -521,6 +522,14 @@ class MotorRecord(Assembly): name="description", is_setting=True, ) + + if has_park_pv: + self._append( + AdjustablePv, + self.pvname + "_KILL", + name="parked", + is_setting=True, + ) if backlash_definition: self._append( AdjustablePv, diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index 2e4326e..ea3814d 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -217,10 +217,16 @@ class StageLxtDelay(Assembly): else: ps_pos = self.offset_coarse_adj.get_current_value() + delay pd_pos = self.offset_fine_adj.get_current_value() - return ( - self._direction.get_current_value() * pd_pos, - self._direction.get_current_value() * ps_pos, - ) + + if pd_pos is None: + outfine = None + else: + outfine = self._direction.get_current_value() * pd_pos, + if ps_pos is None: + outcoarse = None + else: + outcoarse = self._direction.get_current_value() * ps_pos, + return (outfine,outcoarse) class Stage_LXT_Delay(AdjustableVirtual): diff --git a/eco/utilities/feedback.py b/eco/utilities/feedback.py new file mode 100644 index 0000000..2b68893 --- /dev/null +++ b/eco/utilities/feedback.py @@ -0,0 +1,49 @@ +from simple_pid import PID +from ..epics.detector import DetectorPvDataStream +from ..elements.assembly import Assembly +from threading import Thread +from time import sleep +from ..elements.adjustable import AdjustableFS + +class Feedback_Timetool(Assembly): + def __init__(self, name=None, pvname=None, control_adj = None, pid=[1, 0.01, 0], output_limits=(-100,100), setpoint=1060, calib_s_per_px=3e-15): + super().__init__(name=name) + self._append(DetectorPvDataStream, pvname, name="monitor") + self.pid = PID( + *pid, + setpoint=0, + output_limits=(output_limits[0]*abs(calib_s_per_px), output_limits[1]*abs(calib_s_per_px)), + sample_time=10, + ) + self.control_adj = control_adj + self._append( + AdjustableFS, + "/photonics/home/gac-bernina/eco/configuration/tt_feedback_setpoint", + default_value=setpoint, + name="setpoint", + ) + self._append( + AdjustableFS, + "/photonics/home/gac-bernina/eco/configuration/tt_feedback_calib_s_per_px", + default_value=calib_s_per_px, + name="calib_s_per_px", + ) + self._running=False + def stop(self): + self._running = False + def run_continuously(self): + while(self._running): + rb_val = self.monitor.get_current_value() + set_val = self.pid(rb_val-self.setpoint())*self.calib_s_per_px() + print(f"moving phase control adjustable by {set_val}") + self.control_adj.mvr(set_val) + sleep(60) + + + def start_feedback(self): + self._running=True + self.feedback = Thread(target = self.run_continuously) + + + + diff --git a/eco/utilities/runtable.py b/eco/utilities/runtable.py index cbfe5f6..80fc9de 100644 --- a/eco/utilities/runtable.py +++ b/eco/utilities/runtable.py @@ -386,10 +386,6 @@ class Run_Table2: def __repr__(self): return self.__str__() - ###### diagnostic and convencience functions ###### - def run_table_from_old_pgroup(pgroup): - return - def check_timeouts(self, include_bad_adjustables=True, plot=True, repeats=1): return self._data.check_timeouts(include_bad_adjustables=include_bad_adjustables, plot=plot, repeats=repeats) diff --git a/eco/xoptics/dcm_new.py b/eco/xoptics/dcm_new.py index 36df4d5..d7378ed 100644 --- a/eco/xoptics/dcm_new.py +++ b/eco/xoptics/dcm_new.py @@ -17,6 +17,7 @@ from ..devices_general.utilities import Changer from ..elements.assembly import Assembly from eco.xoptics.dcm_pathlength_compensation import MonoTimecompensation + @spec_convenience @update_changes @tweak_option @@ -28,7 +29,7 @@ class DoubleCrystalMono(Assembly): energy_sp="SAROP21-ARAMIS:ENERGY_SP", energy_rb="SAROP21-ARAMIS:ENERGY", fel=None, - las = None, + las=None, undulator_deadband_eV=None, ): super().__init__(name=name) @@ -36,6 +37,29 @@ class DoubleCrystalMono(Assembly): self._las = las self.undulator_deadband_eV = undulator_deadband_eV self.pvname = pvname + + self._append( + AdjustablePvEnum, + self.pvname + ":MODE", + pvname_set=self.pvname + ":MODE_SP", + name="mode", + ) + + self._append( + AdjustablePvEnum, + self.pvname + ":CRYSTAL", + pvname_set=self.pvname + ":CRYSTAL_SP", + name="crystal", + ) + + self._append( + AdjustablePvEnum, + self.pvname + ":DIFF_ORDER", + name="diffraction_order", + ) + + self._append(DcmConfig, self.pvname, name="mono_config") + self._append( MotorRecord_new, pvname + ":RX12", @@ -62,6 +86,15 @@ class DoubleCrystalMono(Assembly): pvname + ":RZ1", name="roll1", is_setting=True, + has_park_pv=True, + view_toplevel_only=True, + ) + self._append( + AdjustablePv, + pvname + ":PIEZO1_VOLTAGE_SP", + pvreadbackname=pvname + ":PIEZO1_VOLTAGE", + name="roll1_piezo", + is_setting=True, view_toplevel_only=True, ) self._append( @@ -76,12 +109,21 @@ class DoubleCrystalMono(Assembly): pvname + ":RX2", name="pitch2", is_setting=True, + has_park_pv=True, + view_toplevel_only=True, + ) + self._append( + AdjustablePv, + pvname + ":PIEZO2_VOLTAGE_SP", + pvreadbackname=pvname + ":PIEZO2_VOLTAGE", + name="pitch2_piezo", + is_setting=True, view_toplevel_only=True, ) self._append( AdjustablePv, energy_sp, - # pvreadbackname=energy_rb, + pvreadbackname=energy_rb, accuracy=0.5, name="energy", ) @@ -180,6 +222,62 @@ class DoubleCrystalMono(Assembly): self.energy._pvreadback.clear_callbacks() +class DcmConfig(Assembly): + def __init__(self, pvbase, name=None): + super().__init__(name=name) + self.pvbase = pvbase + + self._append(DetectorPvData, self.pvbase + ":PITCH1_OFF", name="pitch1_offset") + self._append(DetectorPvData, self.pvbase + ":ROLL1_OFF", name="roll1_offset") + self._append(DetectorPvData, self.pvbase + ":PITCH2_OFF", name="pitch2_offset") + self._append(DetectorPvData, self.pvbase + ":ROLL2_OFF", name="roll2_offset") + self._append(DetectorPvData, self.pvbase + ":T2_OFF", name="gap_offset") + self._append(DetectorPvData, self.pvbase + ":TX_OFF", name="x_offset") + self._append(DetectorPvData, self.pvbase + ":T2_MIN", name="gap_min") + self._append(DetectorPvData, self.pvbase + ":T2_MAX", name="gap_max") + self._append(DcmConfigSet, self.pvbase, "CRY1", name="config_Si111") + self._append(DcmConfigSet, self.pvbase, "CRY2", name="config_Si311") + self._append(DcmConfigSet, self.pvbase, "CRY3", name="config_InSb111") + + +class DcmConfigSet(Assembly): + # SAROP21-ODCM098:PITCH1_CRY1_OFF + def __init__(self, pvbase, par_set_name=None, name=None): + super().__init__(name=name) + self.pvbase = pvbase + self.par_set_name = par_set_name + self._append( + AdjustablePv, + self.pvbase + ":PITCH1_" + self.par_set_name + "_OFF", + name="pitch1_offset", + ) + self._append( + AdjustablePv, + self.pvbase + ":ROLL1_" + self.par_set_name + "_OFF", + name="roll1_offset", + ) + self._append( + AdjustablePv, + self.pvbase + ":PITCH2_" + self.par_set_name + "_OFF", + name="pitch2_offset", + ) + self._append( + AdjustablePv, + self.pvbase + ":ROLL2_" + self.par_set_name + "_OFF", + name="roll2_offset", + ) + self._append( + AdjustablePv, + self.pvbase + ":T2_" + self.par_set_name + "_OFF", + name="gap_offset", + ) + self._append( + AdjustablePv, + self.pvbase + ":TX_" + self.par_set_name + "_OFF", + name="x_offset", + ) + + @spec_convenience @default_representation class EcolEnergy(Assembly): From 7ccb05479a1c5151404bbf8dfd41bd8ec34bc94c Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Fri, 29 Sep 2023 13:33:30 +0200 Subject: [PATCH 52/52] fixed some deprecation errors in run_table, fixes in xrd kappa --- eco/bernina/bernina.py | 317 +++++++------ eco/devices_general/motors.py | 440 ++++++++++++++++++ eco/endstations/bernina_diffractometers.py | 16 +- .../bernina_sample_environments.py | 46 +- eco/loptics/bernina_laser.py | 6 +- eco/microscopes/microscopes.py | 37 ++ eco/timing/timing_diag.py | 2 +- eco/utilities/elog_scilog.py | 2 +- eco/utilities/runtable.py | 15 +- eco/xdiagnostics/profile_monitors.py | 2 +- eco/xoptics/att_usd.py | 4 +- eco/xoptics/reflaser.py | 2 +- 12 files changed, 712 insertions(+), 177 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index c27f2e3..84d0b3b 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -44,35 +44,38 @@ from eco.elements.adj_obj import AdjustableObject namespace.append_obj(AdjustableObject, _config_bernina_dict, name="config_bernina") -#namespace.append_obj( -# "Elog", -# "https://elog-gfa.psi.ch/Bernina", -# screenshot_directory="/tmp", -# name="elog_gfa", -# module_name="eco.utilities.elog", -#) - -#namespace.append_obj( -# "Elog", -# pgroup_adj=config_bernina.pgroup, -# name="scilog", -# module_name="eco.utilities.elog_scilog", -#) - -#namespace.append_obj( -# "ElogsMultiplexer", -# scilog, -# elog_gfa, -# name="elog", -# module_name="eco.utilities.elog", -#) namespace.append_obj( "Elog", "https://elog-gfa.psi.ch/Bernina", screenshot_directory="/tmp", + name="elog_gfa", + module_name="eco.utilities.elog", + lazy=True, +) + +namespace.append_obj( + "Elog", + pgroup_adj=config_bernina.pgroup, + name="scilog", + module_name="eco.utilities.elog_scilog", + lazy=True, +) + +namespace.append_obj( + "ElogsMultiplexer", + scilog, + elog_gfa, name="elog", module_name="eco.utilities.elog", + lazy=True, ) +# namespace.append_obj( +# "Elog", +# "https://elog-gfa.psi.ch/Bernina", +# screenshot_directory="/tmp", +# name="elog", +# module_name="eco.utilities.elog", +# ) eco.ELOG = elog namespace.append_obj( @@ -109,7 +112,7 @@ namespace.append_obj( "EventWorker", name="bs_worker", module_name="escape.stream", - lazy=False, + lazy=True, ) namespace.append_obj( @@ -200,19 +203,19 @@ namespace.append_obj( "SlitBladesGeneral", name="slit_kb", def_blade_up={ - "args": [SmaractRecord, "SARES23:LIC2"], + "args": [SmaractRecord, "SARES23-LIC:MOT_2"], "kwargs": {}, }, def_blade_down={ - "args": [SmaractRecord, "SARES23:LIC1"], + "args": [SmaractRecord, "SARES23-LIC:MOT_1"], "kwargs": {}, }, def_blade_left={ - "args": [SmaractRecord, "SARES23:LIC9"], + "args": [SmaractRecord, "SARES23-LIC:MOT_9"], "kwargs": {}, }, def_blade_right={ - "args": [SmaractRecord, "SARES23:LIC4"], + "args": [SmaractRecord, "SARES23-LIC:MOT_4"], "kwargs": {}, }, module_name="eco.xoptics.slits", @@ -254,19 +257,19 @@ namespace.append_obj( "SlitBladesGeneral", name="slit_cleanup", def_blade_up={ - "args": [SmaractRecord, "SARES23:LIC6"], + "args": [SmaractRecord, "SARES23-LIC:MOT_6"], "kwargs": {}, }, def_blade_down={ - "args": [SmaractRecord, "SARES23:LIC5"], + "args": [SmaractRecord, "SARES23-LIC:MOT_5"], "kwargs": {}, }, def_blade_left={ - "args": [SmaractRecord, "SARES23:LIC8"], + "args": [SmaractRecord, "SARES23-LIC:MOT_8"], "kwargs": {}, }, def_blade_right={ - "args": [SmaractRecord, "SARES23:LIC7"], + "args": [SmaractRecord, "SARES23-LIC:MOT_7"], "kwargs": {}, }, module_name="eco.xoptics.slits", @@ -473,7 +476,7 @@ namespace.append_obj( namespace.append_obj( "SolidTargetDetectorBerninaUSD", - "SARES23:LIC12", + "SARES23-LIC:MOT_12", # diode_channels_raw={ # "up": "", # "down": "", @@ -552,13 +555,13 @@ namespace.append_obj( "ProfKbBernina", module_name="eco.xdiagnostics.profile_monitors", name="prof_kb", - pvname_mirror="SARES23:LIC11", + pvname_mirror="SARES23-LIC:MOT_11", lazy=True, ) namespace.append_obj( "TimetoolBerninaUSD", module_name="eco.timing.timing_diag", - pvname_mirror="SARES23:LIC11", + pvname_mirror="SARES23-LIC:MOT_11", name="tt_kb", lazy=True, ) @@ -797,7 +800,6 @@ namespace.append_obj( configuration=config_bernina.xrd_config(), detectors=[ {"name": "det_diff", "jf_id": "JF01T03V01"}, - {"name": "det_fluo", "jf_id": "JF04T01V01"}, ], pgroup_adj=config_bernina.pgroup, configsjf_adj=config_JFs, @@ -879,15 +881,16 @@ namespace.append_obj( lazy=True, ) -namespace.append_obj( - "DetectorRobot", - JF_detector_id="JF01T03V01", - JF_detector_name="det_diff", - pgroup_adj=config_bernina.pgroup, - config_adj=config_JFs, - module_name="eco.endstations.bernina_robot", - name="robot", -) +#namespace.append_obj( +# "DetectorRobot", +# JF_detector_id="JF01T03V01", +# JF_detector_name="det_diff", +# pgroup_adj=config_bernina.pgroup, +# config_adj=config_JFs, +# module_name="eco.endstations.bernina_robot", +# lazy=True, +# name="robot", +#) namespace.append_obj( "MpodModule", @@ -896,6 +899,7 @@ namespace.append_obj( ["ch1", "ch2", "ch3", "ch4"], module_string="LV_OMPV_1", name="power_LV_patch1", + lazy=True, module_name="eco.devices_general.powersockets", ) @@ -906,6 +910,7 @@ namespace.append_obj( ["ch1", "ch2", "ch3", "ch4"], module_string="LV_OMPV_1", name="power_LV_patch2", + lazy=True, module_name="eco.devices_general.powersockets", ) @@ -1036,12 +1041,15 @@ def _append_namesace_status_to_scan( def _write_namespace_status_to_scan( - scan, daq=daq, namespace=namespace, append_status_info=True, **kwargs + scan, daq=daq, namespace=namespace, append_status_info=True, end_scan=True, **kwargs ): if not append_status_info: return - namespace_status = namespace.get_status(base=None) - scan.status["status_run_end"] = namespace_status + if end_scan: + namespace_status = namespace.get_status(base=None) + scan.status["status_run_end"] = namespace_status + if (not end_scan) and not (len(scan.values_done) == 1): + return runno = daq.get_last_run_number() pgroup = daq.pgroup tmpdir = Path(f"/sf/bernina/data/{pgroup}/res/tmp/stat_run{runno:04d}") @@ -1066,30 +1074,44 @@ def _write_namespace_status_to_scan( scan.scan_info["scan_parameters"]["status"] = "aux/status.json" -def _write_namespace_aliases_to_scan(scan, daq=daq, **kwargs): - namespace_aliases = namespace.alias.get_all() - runno = daq.get_last_run_number() - pgroup = daq.pgroup - tmpdir = Path(f"/sf/bernina/data/{pgroup}/res/tmp/aliases_run{runno:04d}") - tmpdir.mkdir(exist_ok=True, parents=True) - aliasfile = tmpdir / Path("aliases.json") - if not Path(aliasfile).exists(): - with open(aliasfile, "w") as f: - json.dump(namespace_aliases, f, sort_keys=True, cls=NumpyEncoder, indent=4) - else: - with open(aliasfile, "r+") as f: - f.seek(0) - json.dump(namespace_aliases, f, sort_keys=True, cls=NumpyEncoder, indent=4) - f.truncate() - response = daq.append_aux( - aliasfile.resolve().as_posix(), - pgroup=pgroup, - run_number=runno, - ) - print("####### transfer aliases #######") - print(response.json()) - print("################################") - scan.scan_info["scan_parameters"]["aliases"] = "aux/aliases.json" +def _write_namespace_aliases_to_scan(scan, daq=daq, force=False, **kwargs): + if force or (len(scan.values_done) == 1): + namespace_aliases = namespace.alias.get_all() + runno = daq.get_last_run_number() + pgroup = daq.pgroup + tmpdir = Path(f"/sf/bernina/data/{pgroup}/res/tmp/aliases_run{runno:04d}") + tmpdir.mkdir(exist_ok=True, parents=True) + aliasfile = tmpdir / Path("aliases.json") + if not Path(aliasfile).exists(): + with open(aliasfile, "w") as f: + json.dump( + namespace_aliases, f, sort_keys=True, cls=NumpyEncoder, indent=4 + ) + else: + with open(aliasfile, "r+") as f: + f.seek(0) + json.dump( + namespace_aliases, f, sort_keys=True, cls=NumpyEncoder, indent=4 + ) + f.truncate() + + scan.remaining_tasks.append( + Thread( + target=daq.append_aux, + args=[aliasfile.resolve().as_posix()], + kwargs=dict(pgroup=pgroup, run_number=runno), + ) + ) + scan.remaining_tasks[-1].start() + # response = daq.append_aux( + # aliasfile.resolve().as_posix(), + # pgroup=pgroup, + # run_number=runno, + # ) + print("####### transfer aliases started #######") + # print(response.json()) + # print("################################") + scan.scan_info["scan_parameters"]["aliases"] = "aux/aliases.json" def _message_end_scan(scan, **kwargs): @@ -1163,7 +1185,16 @@ def _copy_scan_info_to_raw(scan, daq=daq, **kwargs): f.truncate() # print(f"Copying info file to run {runno} to the raw directory of {pgroup}.") - response = daq.append_aux(scaninfofile.as_posix(), pgroup=pgroup, run_number=runno) + + scan.remaining_tasks.append( + Thread( + target=daq.append_aux, + args=[scaninfofile.as_posix()], + kwargs=dict(pgroup=pgroup, run_number=runno), + ) + ) + scan.remaining_tasks[-1].start() + # response = daq.append_aux(scaninfofile.as_posix(), pgroup=pgroup, run_number=runno) # print(f"Status: {response.json()['status']} Message: {response.json()['message']}") # print( # f"--> creating and copying file took{time.time()-t_start} s, presently adding to deadtime." @@ -1344,15 +1375,29 @@ callbacks_start_scan.append(_increment_daq_run_number) callbacks_start_scan.append(append_scan_monitors) callbacks_end_step = [] callbacks_end_step.append(_copy_scan_info_to_raw) +callbacks_end_step.append(_write_namespace_aliases_to_scan) +callbacks_end_step.append( + lambda scan, daq=daq, namespace=namespace, append_status_info=True, end_scan=True, **kwargs: _write_namespace_status_to_scan( + scan, + daq=daq, + namespace=namespace, + append_status_info=append_status_info, + end_scan=False, + **kwargs, + ) +) callbacks_end_scan = [] callbacks_end_scan.append(_write_namespace_status_to_scan) -callbacks_end_scan.append(_write_namespace_aliases_to_scan) callbacks_end_scan.append(_copy_scan_info_to_raw) +callbacks_end_scan.append( + lambda scan, daq=daq, force=True, **kwargs: _write_namespace_aliases_to_scan( + scan, daq=daq, force=force, **kwargs + ) +) callbacks_end_scan.append(_copy_selected_JF_pedestals_to_raw) callbacks_end_scan.append(end_scan_monitors) callbacks_end_scan.append(_message_end_scan) - # >>>> Extract for run_table and elog @@ -1421,7 +1466,8 @@ def _create_metadata_structure_start_scan( {"elog_post_link": scan._elog[1]._log._url + str(scan._elog_id)} ) except: - print("elog posting failed") + print("Elog posting failed with:") + traceback.print_exc() if not append_status_info: return d = {} @@ -1449,6 +1495,7 @@ namespace.append_obj( pvname="SLAAR21-LTIM01-EVR0:CALCI", thresholds=[0.2, 10], required_fraction=0.6, + lazy=True, name="checker_ioxos_old", ) @@ -1458,6 +1505,7 @@ namespace.append_obj( bs_channel="SAROP21-PBPS133:INTENSITY", thresholds=[0.2, 10], required_fraction=0.6, + lazy=True, name="checker", ) @@ -1653,16 +1701,16 @@ from ..epics.adjustable import AdjustablePv, AdjustablePvEnum # self.motor_configuration = { # "delaystage_both": { -# "id": "SARES23:ESB15", +# "id": "SARES23-USR:MOT_15", # }, # "delaystage_pulse2": { -# "id": "SARES23:ESB1", +# "id": "SARES23-USR:MOT_1", # }, # "wp_both": { -# "id": "SARES23:ESB3", +# "id": "SARES23-USR:MOT_3", # }, # "wp_pulse2": { -# "id": "SARES23:ESB2", +# "id": "SARES23-USR:MOT_2", # }, # } # for name, config in self.motor_configuration.items(): @@ -1740,9 +1788,9 @@ class N2jet(Assembly): class Incoupling(Assembly): def __init__(self, name=None): super().__init__(name=name) - self._append(SmaractRecord, "SARES23:ESB12", name="ver", is_setting=True) - self._append(SmaractRecord, "SARES23:ESB11", name="hor", is_setting=True) - # self._append(SmaractRecord, "SARES23:ESB11", name="x", is_setting=True) + self._append(SmaractRecord, "SARES23-USR:MOT_12", name="ver", is_setting=True) + self._append(SmaractRecord, "SARES23-USR:MOT_11", name="hor", is_setting=True) + # self._append(SmaractRecord, "SARES23-USR:MOT_11", name="x", is_setting=True) # self._append( # MotorRecord, # "SLAAR21-LMOT-M521:MOTOR_1", @@ -1821,20 +1869,20 @@ namespace.append_obj( # class LaserSteering(Assembly): # def __init__(self, name=None): # super().__init__(name=name) -# self._append(SmaractRecord, "SARES23:ESB3", name="mirr1_pitch", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB4", name="mirr1_roll", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB14", name="mirr2_pitch", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB12", name="mirr2_roll", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_3", name="mirr1_pitch", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_4", name="mirr1_roll", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_14", name="mirr2_pitch", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_12", name="mirr2_roll", is_setting=True) # class THzGeneration(Assembly): # def __init__(self, name=None): # super().__init__(name=name) -# self._append(SmaractRecord, "SARES23:LIC16", name="par_x", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB8", name="mirr_x", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB7", name="mirr_z", is_setting=True) -# self._append(SmaractRecord, "SARES23:LIC18", name="mirr_ry", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB9", name="mirr_rz", is_setting=True) -# self._append(SmaractRecord, "SARES23:LIC15", name="polarizer", is_setting=True) +# self._append(SmaractRecord, "SARES23-LIC:MOT_16", name="par_x", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_8", name="mirr_x", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_7", name="mirr_z", is_setting=True) +# self._append(SmaractRecord, "SARES23-LIC:MOT_18", name="mirr_ry", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_9", name="mirr_rz", is_setting=True) +# self._append(SmaractRecord, "SARES23-LIC:MOT_15", name="polarizer", is_setting=True) # class THzVirtualStages(Assembly): @@ -1914,12 +1962,12 @@ namespace.append_obj( # class THz(Assembly): # def __init__(self, name=None): # super().__init__(name=name) -# self._append(SmaractRecord, "SARES23:ESB6", name="par_x", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_6", name="par_x", is_setting=True) # self._append(MotorRecord, "SARES20-MF1:MOT_10", name="par_y", is_setting=True) -# self._append(SmaractRecord, "SARES23:LIC13", name="par_z", is_setting=True) -# self._append(SmaractRecord, "SARES23:LIC14", name="par_rx", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB15", name="par_ry", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB1", name="delaystage_thz", is_setting=True,) +# self._append(SmaractRecord, "SARES23-LIC:MOT_13", name="par_z", is_setting=True) +# self._append(SmaractRecord, "SARES23-LIC:MOT_14", name="par_rx", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_15", name="par_ry", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_1", name="delaystage_thz", is_setting=True,) # self._append(DelayTime, self.delaystage_thz, name="delay_thz", is_setting=False, is_display=True,) # self._append(LaserSteering, name="ir_pointing", is_setting=False) # self._append(THzGeneration, name="generation", is_setting=False) @@ -1945,18 +1993,18 @@ namespace.append_obj( # def __init__(self, name=None): # super().__init__(name=name) -# self._append(SmaractRecord, "SARES23:ESB5", name="crystal_ROT", is_setting=True) -# self._append(SmaractRecord, "SARES23:LIC15", name="ir_1_z", is_setting=True) -# self._append(SmaractRecord, "SARES23:LIC13", name="ir_1_Ry", is_setting=True) -# self._append(SmaractRecord, "SARES23:LIC14", name="ir_1_Rx", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB10", name="ir_2_Rx", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB7", name="ir_2_Ry", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB9", name="para_2_x", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB3", name="thz_mir_x", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB1", name="thz_mir_z", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB8", name="thz_mir_Ry", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB2", name="thz_mir_Rz", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB6", name="focus_z", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_5", name="crystal_ROT", is_setting=True) +# self._append(SmaractRecord, "SARES23-LIC:MOT_15", name="ir_1_z", is_setting=True) +# self._append(SmaractRecord, "SARES23-LIC:MOT_13", name="ir_1_Ry", is_setting=True) +# self._append(SmaractRecord, "SARES23-LIC:MOT_14", name="ir_1_Rx", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_10", name="ir_2_Rx", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_7", name="ir_2_Ry", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_9", name="para_2_x", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_3", name="thz_mir_x", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_1", name="thz_mir_z", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_8", name="thz_mir_Ry", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_2", name="thz_mir_Rz", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_6", name="focus_z", is_setting=True) # self._append( # MotorRecord, # "SARES20-MF1:MOT_4", @@ -1964,13 +2012,13 @@ namespace.append_obj( # is_setting=True, # is_display=True, # ) -# self._append(SmaractRecord, "SARES23:ESB14", name="focus_x", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB13", name="focus_Rz", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB15", name="focus_Ry", is_setting=True) -# self._append(SmaractRecord, "SARES23:ESB11", name="focus_Rx", is_setting=True) -# self._append(SmaractRecord, "SARES23:LIC18", name="thz_wp", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_14", name="focus_x", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_13", name="focus_Rz", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_15", name="focus_Ry", is_setting=True) +# self._append(SmaractRecord, "SARES23-USR:MOT_11", name="focus_Rx", is_setting=True) +# self._append(SmaractRecord, "SARES23-LIC:MOT_18", name="thz_wp", is_setting=True) # self._append( -# SmaractRecord, "SARES23:LIC16", name="delaystage_thz", is_setting=True +# SmaractRecord, "SARES23-LIC:MOT_16", name="delaystage_thz", is_setting=True # ) # self._append(DelayTime, self.delaystage_thz, name="delay_thz", is_setting=True) # self._append( @@ -2041,7 +2089,7 @@ namespace.append_obj( namespace.append_obj( "SmaractController", - "SARES23:LIC", + "SARES23-LIC:MOT_", lazy=True, name="smaract_ust", module_name="eco.motion.smaract", @@ -2049,7 +2097,7 @@ namespace.append_obj( namespace.append_obj( "SmaractController", - "SARES23:ESB", + "SARES23-USR:MOT_", lazy=True, name="smaract_user", module_name="eco.motion.smaract", @@ -2095,7 +2143,7 @@ from ..microscopes import MicroscopeMotorRecord # ) # self._append( # SmaractRecord, -# "SARES23:ESB6", +# "SARES23-USR:MOT_6", # name="horizontal", # is_setting=True, # is_display=True, @@ -2397,7 +2445,7 @@ class Xspect_EH55(Assembly): MotorRecord, "SARES20-MF1:MOT_16", name="y_crystal", is_setting=True ) self._append( - SmaractRecord, "SARES23:ESB17", name="theta_crystal", is_setting=True + SmaractRecord, "SARES23-USR:MOT_17", name="theta_crystal", is_setting=True ) self._append( CameraBasler, @@ -2451,9 +2499,21 @@ class SampleHeaterJet(Assembly): self._append( WagoSensor, pvbase="SARES20-CWAG-GPS01:TEMP-T11", name="sensor_hexapod" ) + self._append( + MpodChannel, + pvbase="SARES21-CPCL-PS7071", + channel_number=5, + name="fan_hexapod_1", + ) + self._append( + MpodChannel, + pvbase="SARES21-CPCL-PS7071", + channel_number=6, + name="fan_hexapod_2", + ) -namespace.append_obj(SampleHeaterJet, name="heater_jet", lazy=True) +#namespace.append_obj(SampleHeaterJet, name="heater_jet", lazy=True) ## sample illumination @@ -2477,20 +2537,9 @@ class IlluminatorsLasers(Assembly): ) + namespace.append_obj(IlluminatorsLasers, name="sample_illumination", lazy=True) -## Timetool feedback -namespace.append_obj( - "Feedback_Timetool", - name="tt_kb_feedback", - pvname="SLAAR21-SPECTT:AT", - control_adj=dummy_adjustable, - lazy=True, - module_name="eco.utilities.feedback", -) - - - ## LIQUID jet setup # from eco.devices_general.wago import AnalogOutput @@ -2559,8 +2608,8 @@ namespace.append_obj( # self._append( # AdjustablePv, "KERNVARIABLES:DELAYBETWEENXFELANDLASER", name="delay" # ) -# self._append(SmaractRecord, "SARES23:ESB18", name="freespace_pitch") -# self._append(SmaractRecord, "SARES23:ESB13", name="freespace_roll") +# self._append(SmaractRecord, "SARES23-USR:MOT_18", name="freespace_pitch") +# self._append(SmaractRecord, "SARES23-USR:MOT_13", name="freespace_roll") # self._append(AnalogOutput, "SARES20-CWAG-GPS01:DAC01", name="shutter1") diff --git a/eco/devices_general/motors.py b/eco/devices_general/motors.py index 6aacd11..80fb3b4 100755 --- a/eco/devices_general/motors.py +++ b/eco/devices_general/motors.py @@ -13,6 +13,7 @@ from ..elements.adjustable import ( update_changes, value_property, ) +from ..devices_general.pv_adjustable import PvRecord from ..elements.detector import DetectorGet from ..epics import get_from_archive from ..utilities.keypress import KeyPress @@ -26,6 +27,7 @@ import numpy as np from .motor_controller import MforceChannel from .detectors import DetectorVirtual from ..epics.detector import DetectorPvData +import json if hasattr(global_config, "elog"): elog = global_config.elog @@ -909,12 +911,450 @@ class MForceSettings(Assembly): self.set_controller_command(f"IS=1,{switch1},{polarity}") self.set_controller_command(f"IS=2,{switch2},{polarity}") +class SmaractSettings(Assembly): + def __init__(self, + pvname, + name=None, + ): + super().__init__(name=name) + self.pvname = pvname + + self._append( + PvRecord, + pvsetname = self.pvname + "_PTYP", + pvreadbackname=self.pvname + "_PTYP_RB", + name="sensor_type_num", + is_setting=True, + ) + self._append( + AdjustablePv, + self.pvname + "_AUTOZERO", + name="autozero_on_homing", + is_setting=True, + ) + self._append( + AdjustablePv, + self.pvname + "_MCLF", + name="max_frequency", + is_setting=True, + ) + + self._append( + AdjustableFS, + file_path="/photonics/home/gac-bernina/eco/configuration/smaract/setting_table", + name="_setting_table", + is_setting=False, + is_display=False, + ) + + def recall(self, stage_alias_or_model=None): + setting_table = self._setting_table() + stages = np.array([(alias, settings["models"]) for alias, settings in setting_table.items()], dtype=object) + if stage_alias_or_model is not None: + if stage_alias_or_model in stages.T[0]: + alias = stage_alias_or_model + else: + idx = [stage_alias_or_model in a for a in stages.T[1]] + if np.sum(idx) == 1: + alias = stages.T[0][idx][0] + if np.sum(idx) > 1: + print("Multiple entries found for model {stage_alias_or_model}. Please check _settings_table") + return + if np.sum(idx ==0 ): + print("No entries found for model {stage_alias_or_model}. Please check _settings_table or model number / alias.") + return + else: + stages = [(alias, settings["models"]) for alias, settings in setting_table.items()] + input_message = "\nSelect the stage to load setting:\n q) quit\n" + input_message += f'{"Idx":>3} {"Alias":<30} {"Models"}\n' + for index, (alias, model) in enumerate(stages): + input_message += f'{index:>3}) {alias:<30} {model}\n' + input_message += 'Input: ' + idx = '' + while idx not in range(len(stages)): + idx = input(input_message) + if idx == 'q': + return + else: + try: + idx = int(idx) + except: + continue + print(f'Selected stage: {stages[idx]}') + alias = stages[idx][0] + stage_settings = setting_table[alias] + if np.any([mcs in self.pvname for mcs in ["SARES23-USR", "SARES23-LIC"]]): + mcs_code = stage_settings["MCS"] + else: + mcs_code = stage_settings["MCS2"] + stage_settings["settings"]["sensor_type_num"] = mcs_code + self.memory.recall(input_obj=stage_settings) + @spec_convenience @update_changes @get_from_archive @value_property class SmaractRecord(Assembly): + def __init__( + self, + pvname, + name=None, + elog=None, + # alias_fields={"readback": "RBV"}, + alias_fields={}, + backlash_definition=False, + expect_bad_limits=True, + ): + super().__init__(name=name) + # self.settings.append(self) + self.settings_collection.append(self, force=True) + + self.pvname = pvname + self._motor = _Motor(pvname) + self._elog = elog + for an, af in alias_fields.items(): + self.alias.append( + Alias(an, channel=".".join([pvname, af]), channeltype="CA") + ) + self._currentChange = None + + self._append( + SmaractSettings, self.pvname, name="motor_parameters", is_setting=False + ) + self._append( + AdjustablePv, self.pvname + ".LLM", name="limit_low", is_setting=True + ) + self._append( + AdjustablePv, self.pvname + ".HLM", name="limit_high", is_setting=True + ) + self._append( + AdjustablePvEnum, + self.pvname + ".STAT", + name="status_flag", + is_setting=False, + is_display=True, + ) + self._append( + AdjustablePv, + self.pvname + ".ACCL", + name="acceleration_time", + is_setting=True, + ) + self._append( + AdjustablePvEnum, self.pvname + ".DIR", name="direction", is_setting=True + ) + self._append(AdjustablePv, self.pvname + ".OFF", name="offset", is_setting=True) + self._append( + AdjustablePv, self.pvname + ".FOFF", name="force_offset", is_setting=True + ) + self._append(AdjustablePv, self.pvname + ".VELO", name="speed", is_setting=True) + + self._append( + AdjustablePv, + self.pvname + ".HOMR", + name="home_forward", + is_setting=False, + is_status=False, + is_display=False, + ) + self._append( + AdjustablePv, + self.pvname + ".HOMR", + name="home_reverse", + is_setting=False, + is_status=False, + is_display=False, + ) + + self._append( + DetectorPvData, + self.pvname + ".RBV", + name="readback", + is_setting=False, + is_display=True, + ) + + self._append( + AdjustablePvEnum, self.pvname + ".SPMG", name="mode", is_setting=False + ) + self._append( + DetectorPvData, self.pvname + ".MSTA", name="_flags", is_setting=False + ) + self._append( + SmaractRecordFlags, + self.pvname, + self._flags, + name="flags", + is_display="recursive", + is_status=True, + ) + + self._append( + AdjustablePvString, self.pvname + ".EGU", name="unit", is_setting=True + ) + self._append( + AdjustablePvString, + self.pvname + ".DESC", + name="description", + is_setting=True, + ) + self._append( + AdjustablePv, + self.pvname + "_CAL", + name="_calibrate_sensor", + is_setting=True, + is_status=False, + is_display=False, + ) + if backlash_definition: + self._append( + AdjustablePv, + self.pvname + ".BVEL", + name="backlash_velocity", + is_setting=True, + ) + self._append( + AdjustablePv, + self.pvname + ".BACC", + name="backlash_acceleration", + is_setting=True, + ) + self._append( + AdjustablePv, + self.pvname + ".BDST", + name="backlash_distance", + is_setting=True, + ) + self._append( + AdjustablePv, + self.pvname + ".FRAC", + name="backlash_fraction", + is_setting=True, + ) + if expect_bad_limits: + self.check_bad_limits() + + def check_bad_limits(self, abs_set_value=2**53): + ll, hl = self.get_limits() + if ll == 0 and hl == 0: + self.set_limits(-abs_set_value, abs_set_value) + + def home(self): + self.home_forward(1) + time.sleep(0.1) + while not self.flags.is_homed.get_current_value(): + time.sleep(0.1) + + def calibrate_sensor(self): + self._calibrate_sensor(1) + time.sleep(0.1) + while not self.flags.motion_complete.get_current_value(): + time.sleep(0.1) + + def set_target_value(self, value, hold=False, check=True): + """Adjustable convention""" + + def changer(value): + self._status = self._motor.move(value, ignore_limits=(not check), wait=True) + self._status_message = _status_messages[self._status] + if self._status < 0: + raise AdjustableError(self._status_message) + elif self._status > 0: + print("\n") + print(self._status_message) + + # changer = lambda value: self._motor.move(\ + # value, ignore_limits=(not check), + # wait=True) + return Changer( + target=value, + parent=self, + changer=changer, + hold=hold, + stopper=self._motor.stop, + ) + + def stop(self): + """Adjustable convention""" + try: + self._currentChange.stop() + except: + self.mode.set_target_value(0) + pass + + def get_current_value(self, posType="user", readback=True): + """Adjustable convention""" + _keywordChecker([("posType", posType, _posTypes)]) + if posType == "user": + return self._motor.get_position(readback=readback) + if posType == "dial": + return self._motor.get_position(readback=readback, dial=True) + if posType == "raw": + return self._motor.get_position(readback=readback, raw=True) + + def reset_current_value_to(self, value, posType="user"): + """Adjustable convention""" + _keywordChecker([("posType", posType, _posTypes)]) + if posType == "user": + return self._motor.set_position(value) + if posType == "dial": + return self._motor.set_position(value, dial=True) + if posType == "raw": + return self._motor.set_position(value, raw=True) + + def get_moveDone(self): + """Adjustable convention""" + """ 0: moving 1: move done""" + return PV(str(self.Id + ".DMOV")).value + + def set_limits( + self, low_limit, high_limit, posType="user", relative_to_present=False + ): + """ + set limits. usage: set_limits(low_limit, high_limit) + + """ + _keywordChecker([("posType", posType, _posTypes)]) + ll_name, hl_name = "LLM", "HLM" + if posType == "dial": + ll_name, hl_name = "DLLM", "DHLM" + if relative_to_present: + v = self.get_current_value(posType=posType) + low_limit = v + low_limit + high_limit = v + high_limit + self._motor.put(ll_name, low_limit) + self._motor.put(hl_name, high_limit) + + def add_value_callback(self, callback, index=None): + return self._motor.get_pv("RBV").add_callback(callback=callback, index=index) + + def clear_value_callback(self, index=None): + if index: + self._motor.get_pv("RBV").remove_callback(index) + else: + self._motor.get_pv("RBV").clear_callbacks() + + def get_limits(self, posType="user"): + """Adjustable convention""" + _keywordChecker([("posType", posType, _posTypes)]) + ll_name, hl_name = "LLM", "HLM" + if posType == "dial": + ll_name, hl_name = "DLLM", "DHLM" + return self._motor.get(ll_name), self._motor.get(hl_name) + + def gui(self): + pv, m = tuple(self.pvname.split(":")) + self._run_cmd(f'caqtdm -macro "P={pv},M=:{m}, T=MCS" /sf/controls/config/qt/motorx_all.ui') + + def gui_extra(self): + pv, m = tuple(self.pvname.split(":")) + self._run_cmd(f'caqtdm -macro "P={pv},M={m}" /ioc/modules/qt/MCS_extra.ui') + + # return string with motor value as variable representation + def __str__(self): + # """ return short info for the current motor""" + s = f"{self.name}" + s += f"\t@ {colorama.Style.BRIGHT}{self.get_current_value():1.6g}{colorama.Style.RESET_ALL} (dial @ {self.get_current_value(posType='dial'):1.6g}; stat: {self.status_flag().name})" + # # s += "\tuser limits (low,high) : {:1.6g},{:1.6g}\n".format(*self.get_limits()) + s += f"\n{colorama.Style.DIM}low limit {colorama.Style.RESET_ALL}" + s += ValueInRange(*self.get_limits()).get_str(self.get_current_value()) + s += f" {colorama.Style.DIM}high limit{colorama.Style.RESET_ALL}" + # # s += "\tuser limits (low,high) : {:1.6g},{1.6g}".format(self.get_limits()) + return s + + def __repr__(self): + print(str(self)) + return object.__repr__(self) + + def __call__(self, value): + self._currentChange = self.set_target_value(value) + + def _tweak_ioc(self, step_value=None): + pv = self._motor.get_pv("TWV") + pvf = self._motor.get_pv("TWF") + pvr = self._motor.get_pv("TWR") + if not step_value: + step_value = pv.get() + print(f"Tweaking {self.name} at step size {step_value}", end="\r") + + help = "q = exit; up = step*2; down = step/2, left = neg dir, right = pos dir\n" + help = help + "g = go abs, s = set" + print(f"tweaking {self.name}") + print(help) + print(f"Starting at {self.get_current_value()}") + step_value = float(step_value) + oldstep = 0 + k = KeyPress() + cll = colorama.ansi.clear_line() + + class Printer: + def print(self, **kwargs): + print( + cll + f"stepsize: {self.stepsize}; current: {kwargs['value']}", + end="\r", + ) + + p = Printer() + print(" ") + p.stepsize = step_value + p.print(value=self.get_current_value()) + ind_callback = self.add_value_callback(p.print) + pv.put(step_value) + while k.isq() is False: + if oldstep != step_value: + p.stepsize = step_value + p.print(value=self.get_current_value()) + oldstep = step_value + k.waitkey() + if k.isu(): + step_value = step_value * 2.0 + pv.put(step_value) + elif k.isd(): + step_value = step_value / 2.0 + pv.put(step_value) + elif k.isr(): + pvf.put(1) + elif k.isl(): + pvr.put(1) + elif k.iskey("g"): + print("enter absolute position (char to abort go to)") + sys.stdout.flush() + v = sys.stdin.readline() + try: + v = float(v.strip()) + self.set_target_value(v) + except: + print("value cannot be converted to float, exit go to mode ...") + sys.stdout.flush() + elif k.iskey("s"): + print("enter new set value (char to abort setting)") + sys.stdout.flush() + v = sys.stdin.readline() + try: + v = float(v[0:-1]) + self.reset_current_value_to(v) + except: + print("value cannot be converted to float, exit go to mode ...") + sys.stdout.flush() + elif k.isq(): + break + else: + print(help) + self.clear_value_callback(index=ind_callback) + print(f"final position: {self.get_current_value()}") + print(f"final tweak step: {pv.get()}") + + def tweak(self, *args, **kwargs): + return self._tweak_ioc(*args, **kwargs) + + +@spec_convenience +@update_changes +@get_from_archive +@value_property +class SmaractRecord_old(Assembly): + #Note: this is the one that works with the old SmarAct IOCs before Thierry made changes in 09/2023 def __init__( self, pvname, diff --git a/eco/endstations/bernina_diffractometers.py b/eco/endstations/bernina_diffractometers.py index aa9e30d..7c32a9d 100644 --- a/eco/endstations/bernina_diffractometers.py +++ b/eco/endstations/bernina_diffractometers.py @@ -845,10 +845,12 @@ class XRDYou(Assembly): kappa_angle=60, degrees=True, bernina_kappa=True, - invert_elbow=False, + invert_elbow=None, ): """tool to convert from you definition angles to kappa angles, in particular the bernina kappa where the""" + if invert_elbow is None: + invert_elbow = self.invert_kappa_ellbow if bernina_kappa: eta = -eta phi = -phi @@ -869,16 +871,16 @@ class XRDYou(Assembly): if bernina_kappa: eta_k = eta_k - np.pi / 2 kappa = -kappa - if False: + if True: def flip_ang(ang): - if 1 < abs(ang // np.pi): + if 2 <= abs(ang // np.pi): return ang - np.sign(ang) * np.pi * 2 else: return ang - # phi_k = flip_ang(phi_k) - phi_k = phi_k + np.pi * 2 + phi_k = flip_ang(phi_k) + # phi_k = phi_k + np.pi * 2 eta_k = flip_ang(eta_k) kappa = flip_ang(kappa) if degrees: @@ -893,8 +895,10 @@ class XRDYou(Assembly): kappa_angle=60, degrees=True, bernina_kappa=True, - invert_elbow=False, + invert_elbow=None, ): + if invert_elbow is None: + invert_elbow = self.invert_kappa_ellbow if degrees: eta_k, kappa, phi_k, kappa_angle = np.deg2rad( [eta_k, kappa, phi_k, kappa_angle] diff --git a/eco/endstations/bernina_sample_environments.py b/eco/endstations/bernina_sample_environments.py index fd6aab6..62fa09f 100644 --- a/eco/endstations/bernina_sample_environments.py +++ b/eco/endstations/bernina_sample_environments.py @@ -43,8 +43,8 @@ class High_field_thz_chamber(Assembly): self.par_out_pos = [35, -9.5] self.motor_configuration = { "rx": { - # "id": "SARES23:ESB13", - "id": "SARES23:ESB6", + # "id": "SARES23-USR:MOT_13", + "id": "SARES23-USR:MOT_6", "pv_descr": "Motor7:1 THz Chamber Rx", "type": 2, "sensor": 1, @@ -53,8 +53,8 @@ class High_field_thz_chamber(Assembly): "kwargs": {"accuracy": 0.01}, }, "x": { - # "id": "SARES23:ESB14", - "id": "SARES23:ESB15", + # "id": "SARES23-USR:MOT_14", + "id": "SARES23-USR:MOT_15", "pv_descr": "Motor7:2 THz Chamber x ", "type": 1, "sensor": 0, @@ -62,8 +62,8 @@ class High_field_thz_chamber(Assembly): "home_direction": "back", }, "z": { - # "id": "SARES23:ESB10", - "id": "SARES23:LIC16", + # "id": "SARES23-USR:MOT_10", + "id": "SARES23-LIC:MOT_16", "pv_descr": "Motor6:1 THz Chamber z ", "type": 1, "sensor": 0, @@ -71,8 +71,8 @@ class High_field_thz_chamber(Assembly): "home_direction": "back", }, "ry": { - # "id": "SARES23:ESB11", - "id": "SARES23:LIC15", + # "id": "SARES23-USR:MOT_11", + "id": "SARES23-LIC:MOT_15", "pv_descr": "Motor6:2 THz Chamber Ry", "type": 2, "sensor": 1, @@ -80,8 +80,8 @@ class High_field_thz_chamber(Assembly): "home_direction": "back", }, "rz": { - # "id": "SARES23:ESB12", - "id": "SARES23:ESB4", + # "id": "SARES23-USR:MOT_12", + "id": "SARES23-USR:MOT_4", "pv_descr": "Motor6:3 THz Chamber Rz", "type": 2, "sensor": 1, @@ -292,7 +292,7 @@ class Organic_crystal_breadboard(Assembly): self.motor_configuration = { "mir_x": { # "id": "-LIC17", - "id": ":ESB8", + "id": "-USR:MOT_8", "pv_descr": "Motor8:2 THz mirror x ", "type": 1, "sensor": 13, @@ -301,7 +301,7 @@ class Organic_crystal_breadboard(Assembly): }, "mir_rz": { # "id": "-LIC18", - "id": ":ESB9", + "id": "-USR:MOT_9", "pv_descr": "Motor8:3 THz mirror rz ", "type": 1, "sensor": 13, @@ -310,7 +310,7 @@ class Organic_crystal_breadboard(Assembly): }, "mir_ry": { # "id": "-ESB1", - "id": ":LIC18", + "id": "-LIC:MOT_18", "pv_descr": "Motor3:1 THz mirror ry ", "type": 2, "sensor": 1, @@ -319,7 +319,7 @@ class Organic_crystal_breadboard(Assembly): }, "mir_z": { # "id": "-LIC16", - "id": ":ESB7", + "id": "-USR:MOT_7", "pv_descr": "Motor8:1 THz mirror z", "type": 1, "sensor": 13, @@ -328,7 +328,7 @@ class Organic_crystal_breadboard(Assembly): }, "par_x": { # "id": "-ESB3", - "id": ":LIC17", + "id": "-LIC:MOT_17", "pv_descr": "Motor3:3 THz parabola2 x", "type": 1, "sensor": 0, @@ -337,7 +337,7 @@ class Organic_crystal_breadboard(Assembly): }, "delaystage_thz": { # "id": "-ESB18", - "id": ":ESB1", + "id": "-USR:MOT_1", "pv_descr": "Motor8:3 NIR delay stage", "type": 1, "sensor": 0, @@ -346,7 +346,7 @@ class Organic_crystal_breadboard(Assembly): }, "nir_m1_ry": { # "id": "-ESB17", - "id": ":ESB3", + "id": "-USR:MOT_3", "pv_descr": "Motor8:2 near IR mirror 1 ry", "type": 2, "sensor": 1, @@ -354,7 +354,7 @@ class Organic_crystal_breadboard(Assembly): "home_direction": "back", }, "nir_m1_rx": { - "id": ":ESB16", + "id": "-USR:MOT_16", "pv_descr": "Motor8:1 near IR mirror 1 rx", "type": 2, "sensor": 1, @@ -363,7 +363,7 @@ class Organic_crystal_breadboard(Assembly): }, "nir_m2_ry": { # "id": "-ESB9", - "id": ":ESB14", + "id": "-USR:MOT_14", "pv_descr": "Motor5:3 near IR mirror 2 ry", "type": 2, "sensor": 1, @@ -371,8 +371,8 @@ class Organic_crystal_breadboard(Assembly): "home_direction": "back", }, "nir_m2_rx": { - # "id": ":ESB4", - "id": ":ESB12", + # "id": "-USR:MOT_4", + "id": "-USR:MOT_12", "pv_descr": "Motor4:1 near IR mirror 2 rx", "type": 1, "sensor": 13, @@ -380,7 +380,7 @@ class Organic_crystal_breadboard(Assembly): "home_direction": "back", }, "crystal": { - "id": ":ESB2", + "id": "-USR:MOT_2", "pv_descr": "Motor3:2 crystal rotation", "type": 2, "sensor": 1, @@ -388,7 +388,7 @@ class Organic_crystal_breadboard(Assembly): "home_direction": "back", }, "wp": { - "id": ":ESB7", + "id": "-USR:MOT_7", "pv_descr": "Motor5:1 waveplate rotation", "type": 2, "sensor": 1, diff --git a/eco/loptics/bernina_laser.py b/eco/loptics/bernina_laser.py index ea3814d..91875e8 100644 --- a/eco/loptics/bernina_laser.py +++ b/eco/loptics/bernina_laser.py @@ -21,9 +21,9 @@ ureg = UnitRegistry() class IncouplingCleanBernina(Assembly): def __init__(self, name=None): super().__init__(name=name) - self._append(SmaractRecord, "SARES23:LIC17", name="tilt") - self._append(SmaractRecord, "SARES23:LIC18", name="rotation") - self._append(SmaractRecord, "SARES23:LIC16", name="transl_vertical") + self._append(SmaractRecord, "SARES23-LIC:MOT_17", name="tilt") + self._append(SmaractRecord, "SARES23-LIC:MOT_18", name="rotation") + self._append(SmaractRecord, "SARES23-LIC:MOT_16", name="transl_vertical") self._append(MotorRecord, "SARES20-MF2:MOT_5", name="transl_horizontal") diff --git a/eco/microscopes/microscopes.py b/eco/microscopes/microscopes.py index 1d0d331..fa72798 100644 --- a/eco/microscopes/microscopes.py +++ b/eco/microscopes/microscopes.py @@ -108,3 +108,40 @@ class OptoSigmaZoom(Assembly): def set_target_value(self, value, **kwargs): return self.zoom.set_target_value(value, **kwargs) + + +@spec_convenience +class FeturaPlusZoom(Assembly): + def __init__( + self, + pv_get_position="SARES20-FETURA:POS_RB", + pv_set_position="SARES20-FETURA:POS_SP", + + name=None, + ): + super().__init__(name=name) + self.settings_collection.append(self) + self._append( + AdjustablePv, + pv_set_position, + pv_get_position, + accuracy=1, + name="zoom_raw", + is_setting=False, + ) + + self._append( + AdjustableVirtual, + [self.zoom_raw], + lambda x: abs(round(x / 1000 * 100) - 100), + lambda x: round(abs(x - 100) / 100 * 1000), + name="zoom", + is_setting=False, + ) + + def get_current_value(self): + return self.zoom.get_current_value() + + def set_target_value(self, value, **kwargs): + return self.zoom.set_target_value(value, **kwargs) + diff --git a/eco/timing/timing_diag.py b/eco/timing/timing_diag.py index 975f949..681cb5d 100644 --- a/eco/timing/timing_diag.py +++ b/eco/timing/timing_diag.py @@ -30,7 +30,7 @@ class TimetoolBerninaUSD(Assembly): spectrometer_pvname="SARES20-CAMS142-M5", microscope_pvname="SARES20-PROF141-M1", delaystage_PV="SLAAR21-LMOT-M524:MOTOR_1", - pvname_mirror="SARES23:LIC9", + pvname_mirror="SARES23-LIC:MOT_9", pvname_zoom="SARES20-MF1:MOT_8", mirror_in=15, mirror_out=-5, diff --git a/eco/utilities/elog_scilog.py b/eco/utilities/elog_scilog.py index e45ab4b..136ece4 100755 --- a/eco/utilities/elog_scilog.py +++ b/eco/utilities/elog_scilog.py @@ -27,7 +27,7 @@ def getDefaultElogInstance( with open(os.path.join(home, ".scilog_psi"), "r") as f: _pw = f.read().strip() except: - print("Enter scilog password for user: %s" % kwargs["user"]) + print(f"Enter scilog password for user: {user}") _pw = _getpass() kwargs.update(dict(password=_pw)) log = SciLog(url, options := {"username": user, "password": kwargs["password"]}) diff --git a/eco/utilities/runtable.py b/eco/utilities/runtable.py index 80fc9de..ac2d1bd 100644 --- a/eco/utilities/runtable.py +++ b/eco/utilities/runtable.py @@ -76,7 +76,8 @@ class Gsheet_API: def _append_to_gspread_key_df(self, gspread_key_df): if os.path.exists(self._keydf_fname): self._key_df = pd.read_pickle(self._keydf_fname) - self._key_df = self._key_df.append(gspread_key_df) + #deprecated: self._key_df = self._key_df.append(gspread_key_df) + self._key_df = pd.concat([self._key_df, gspread_key_df]) self._key_df.to_pickle(self._keydf_fname) else: self._key_df.to_pickle(self._keydf_fname) @@ -100,6 +101,7 @@ class Gsheet_API: {"keys": [spreadsheet.id]}, index=[f"{exp_id}"], ) + print(gspread_key_df) spreadsheet_key = spreadsheet.id self._append_to_gspread_key_df(gspread_key_df) self._spreadsheet_key = spreadsheet_key @@ -490,13 +492,15 @@ class Run_Table_DataFrame(DataFrame): multiindex = pd.MultiIndex.from_tuples( [(dev, adj) for dev in dat.keys() for adj in dat[dev].keys()], names=names ) - values = np.array([val for adjs in dat.values() for val in adjs.values()]) + values = np.array([val for adjs in dat.values() for val in adjs.values()], dtype=object) index = np.array( [f"{dev}.{adj}" for dev, adjs in dat.items() for adj in adjs.keys()] ) # run_df = DataFrame([values], columns=multiindex, index=[runno]) run_df = DataFrame([values], columns=index, index=[runno]) - self.df = self.append(run_df) + #deprecated: self.df = self.append(run_df) + self.df = pd.concat([self.df, run_df]) + self._remove_duplicates() # self.order_df() self.save() @@ -517,14 +521,15 @@ class Run_Table_DataFrame(DataFrame): multiindex = pd.MultiIndex.from_tuples( [(dev, adj) for dev in dat.keys() for adj in dat[dev].keys()], names=names ) - values = np.array([val for adjs in dat.values() for val in adjs.values()]) + values = np.array([val for adjs in dat.values() for val in adjs.values()], dtype=object) index = np.array( [f"{dev}.{adj}" for dev, adjs in dat.items() for adj in adjs.keys()] ) # pos_df = DataFrame([values], columns=multiindex, index=[f"p{posno}"]) pos_df = DataFrame([values], columns=index, index=[f"p{posno}"]) - self.df = self.append(pos_df) + #deprecated: self.df = self.append(pos_df) + self.df = pd.concat([self.df,pos_df]) self._remove_duplicates() # self.order_df() self.save() diff --git a/eco/xdiagnostics/profile_monitors.py b/eco/xdiagnostics/profile_monitors.py index 1e559e5..873bcc8 100755 --- a/eco/xdiagnostics/profile_monitors.py +++ b/eco/xdiagnostics/profile_monitors.py @@ -108,7 +108,7 @@ class ProfKbBernina(Assembly): pvname_target_x="SARES20-MF2:MOT_1", pvname_target_y="SARES20-MF2:MOT_2", pvname_target_z="SARES20-MF2:MOT_3", - pvname_mirror="SARES23:LIC11", + pvname_mirror="SARES23-LIC:MOT_11", mirror_in=15, mirror_out=-5, pvname_zoom="SARES20-MF2:MOT_4", diff --git a/eco/xoptics/att_usd.py b/eco/xoptics/att_usd.py index ec56b0c..7b4e56d 100644 --- a/eco/xoptics/att_usd.py +++ b/eco/xoptics/att_usd.py @@ -21,8 +21,8 @@ class Att_usd(Assembly): self.E = None self.E_min = 1500 self._sleeptime = 1 - self._append(SmaractRecord, "SARES23:LIC10", name="transl_2", is_setting=True, is_display=True) - self._append(SmaractRecord, "SARES23:LIC3", name="transl_1", is_setting=True, is_display=True) + self._append(SmaractRecord, "SARES23-LIC:MOT_10", name="transl_2", is_setting=True, is_display=True) + self._append(SmaractRecord, "SARES23-LIC:MOT_3", name="transl_1", is_setting=True, is_display=True) self.motor_configuration = { "transl_2": { "id": "SARES23-LIC10", diff --git a/eco/xoptics/reflaser.py b/eco/xoptics/reflaser.py index 28464b7..726c5b5 100644 --- a/eco/xoptics/reflaser.py +++ b/eco/xoptics/reflaser.py @@ -10,7 +10,7 @@ from ..elements.assembly import Assembly class RefLaser_BerninaUSD(Assembly): def __init__( self, - pvname_mirrortranslation="SARES23:LIC12", + pvname_mirrortranslation="SARES23-LIC:MOT_12", pvname_onoff="SARES21-CPCL-PS7071:LV_OMPV_1_CH1_SWITCH_SP", elog=None, name=None,