From 4ac8d7f3e192352db07922582bdd5bdd645f7d62 Mon Sep 17 00:00:00 2001 From: Mathias Sander Date: Sat, 2 Dec 2023 18:35:00 +0100 Subject: [PATCH] memory ease of use --- eco/bernina/bernina.py | 64 ++++++++++- eco/devices_general/cameras_swissfel.py | 22 +++- eco/devices_general/pipelines_swissfel.py | 4 +- eco/elements/memory.py | 27 ++++- eco/endstations/bernina_robots.py | 10 +- eco/endstations/bernina_vhamos.py | 10 ++ eco/epics/adjustable.py | 6 + eco/timing/timetool_online_helper.py | 12 +- eco/timing/timing_diag.py | 133 ++++++++++++++++++++++ 9 files changed, 274 insertions(+), 14 deletions(-) create mode 100644 eco/endstations/bernina_vhamos.py diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index bc603bf..f2ceb93 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -204,6 +204,7 @@ namespace.append_obj( namespace.append_obj( "OffsetMirrorsBernina", name="offset", + lazy=True, module_name="eco.xoptics.offsetMirrors_new", ) @@ -234,6 +235,29 @@ namespace.append_obj( lazy=True, ) +namespace.append_obj( + "SolidTargetDetectorPBPS", + "SAROP21-PBPS103", + # 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_mono_new", + module_name="eco.xdiagnostics.intensity_monitors", + # pipeline_computation="SAROP21-PBPS103_proc", + lazy=True, +) + from eco.devices_general.motors import SmaractStreamdevice, SmaractRecord namespace.append_obj( @@ -605,6 +629,13 @@ namespace.append_obj( name="tt_kb", lazy=True, ) +namespace.append_obj( + "TimetoolSpatial", + module_name="eco.timing.timing_diag", + name="tt_spatial_dev", + lazy=True, +) + namespace.append_obj( "HexapodSymmetrie", name="usd_table", @@ -843,7 +874,7 @@ namespace.append_obj( module_name="eco.endstations.bernina_robots", name="rob", pshell_url="http://PC14742:8080/", - lazy=False, + lazy=True, ) namespace.append_obj( @@ -1649,9 +1680,29 @@ namespace.append_obj( # pvname_zoom="SARES20-MF1:MOT_5", # ) + +# from eco.devices_general.cameras_swissfel import FeturaMicroscope +# from eco.elements.assembly import Assembly +# class SpatialTimetool(Assembly): +# def __init__(self, pvname_camera=None, pvname_base_zoom=None, pvname_target_stage = None, name=None): +# super().__init__(name=name) +# self._append(FeturaMicroscope, pvname_camera = pvname_camera, pvname_base_zoom=pvname_base_zoom, name = "camera", camserver_alias=name, is_display="recursive") +# if pvname_target_stage: +# self._append(MotorRecord, pvname = pvname_target_stage, name = "target_transl") +# self._append(MotorRecord,'SARES23-USR:MOT_2', name='delaystage', is_setting=True) + +# namespace.append_obj( +# SpatialTimetool, +# pvname_camera = "SARES20-CAMS142-M4", +# pvname_base_zoom="SARES20-FETURA", +# pvname_target_stage = "SARES20-MF1:MOT_8", +# name="tt_spatial", +# lazy=True, +# ) + namespace.append_obj( "MicroscopeMotorRecord", - "SARES20-CAMS142-C1", + "SARES20-CAMS142-C2", lazy=True, pvname_zoom="SARES20-MF1:MOT_7", name="samplecam_inline", @@ -1660,7 +1711,7 @@ namespace.append_obj( namespace.append_obj( "CameraBasler", - "SLAAR21-LCAM-C532", + "SARES20-CAMS142-M1", lazy=True, name="samplecam_sideview", module_name="eco.devices_general.cameras_swissfel", @@ -1709,6 +1760,13 @@ namespace.append_obj( # Id="SLAAR21-LMOT", # smar_config=config_berninamesp["las_smar_config"], # ) +namespace.append_obj( + "VHamos", + name='vhamos', + pgroup_adj=config_bernina.pgroup, + lazy=True, + module_name="eco.endstations.bernina_vhamos", +) # new version namespace.append_obj( diff --git a/eco/devices_general/cameras_swissfel.py b/eco/devices_general/cameras_swissfel.py index da5bacc..e212a9c 100644 --- a/eco/devices_general/cameras_swissfel.py +++ b/eco/devices_general/cameras_swissfel.py @@ -1,6 +1,7 @@ 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 @@ -282,6 +283,8 @@ class CameraBasler(Assembly): self.pvname = pvname if not camserver_alias: camserver_alias = self.alias.get_full_name() + f" ({pvname})" + else: + camserver_alias = camserver_alias + f" ({pvname})" self._append( CamserverConfig2, self.pvname, @@ -533,7 +536,7 @@ class CameraBasler(Assembly): f'caqtdm -macro "NAME={self.pvname},CAMNAME={self.pvname}" /sf/controls/config/qt/Camera/CameraExpert.ui' ) - +# NB: please note this should be moved to microscopes which are using cameras plus zooms, class QioptiqMicroscope(CameraBasler): def __init__(self, pvname_camera, pvname_zoom=None, pvname_focus=None, name=None): super().__init__(pvname_camera, name=name) @@ -549,6 +552,8 @@ class CameraPCO(Assembly): self.pvname = pvname if not camserver_alias: camserver_alias = self.alias.get_full_name() + f"({pvname})" + else: + camserver_alias = camserver_alias + f"({pvname})" self._append( CamserverConfig, self.pvname, @@ -630,3 +635,18 @@ class CameraPCO(Assembly): self._run_cmd( f'caqtdm -macro "NAME={self.pvname},CAMNAME={self.pvname}" /sf/controls/config/qt/Camera/CameraExpert.ui' ) + + +# NB: please note this should be moved to microscopes which are using cameras plus zooms, +class FeturaMicroscope(CameraPCO): + def __init__(self, pvname_camera, pvname_base_zoom=None, name=None, camserver_alias=None): + super().__init__(pvname_camera, name=name, camserver_alias=camserver_alias) + if pvname_base_zoom: + self._append(AdjustablePv, pvsetname=pvname_base_zoom+":POS_SP", pvreadbackname=pvname_base_zoom+":POS_RB", name="_zoom_motor", is_setting=True, is_display=False) + def getv(v): + return v/10. + def setv(v): + return v*10. + self._append(AdjustableVirtual, [self._zoom_motor], getv, setv, name="zoom", unit="%") + + \ No newline at end of file diff --git a/eco/devices_general/pipelines_swissfel.py b/eco/devices_general/pipelines_swissfel.py index ce7bc8e..0333d50 100644 --- a/eco/devices_general/pipelines_swissfel.py +++ b/eco/devices_general/pipelines_swissfel.py @@ -63,12 +63,12 @@ class Pipeline(Assembly): return get_pipelineclient() def _get_config(self): - return self.pc.get_pipeline_config(self.pipeline_name) + return self.pc.get_instance_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), + changer=lambda v: self.pc.set_instance_config(self.pipeline_name, v), hold=hold, ) diff --git a/eco/elements/memory.py b/eco/elements/memory.py index f79fbd3..7f74f2f 100644 --- a/eco/elements/memory.py +++ b/eco/elements/memory.py @@ -7,6 +7,7 @@ import sys, colorama from inspect import getargspec import eco from ansi2html import Ansi2HTMLConverter +from simple_term_menu import TerminalMenu conv = Ansi2HTMLConverter() @@ -58,11 +59,33 @@ class Memory: row.append(t.strftime("%Y-%m-%d: %a %-H:%M")) row.append(content["message"]) a.append(row) + return tabulate(a, headers=["Index", "Time", "Message"]) - def __call__(self, index): + def __call__(self, index=None, **kwargs): # print(self.get_memory_difference_str(index)) - self.recall(memory_index=index) + + if index is None: + self.setup_path() + mem = self._memories() + a = [] + for n, (key, content) in enumerate(mem.items()): + row = '' + t = datetime.fromisoformat(key) + row += t.strftime("%Y-%m-%d: %a %-H:%M") + row +=' ' + row += content["message"] + a.append(row) + ind_cancel = len(a) + a.append('--> do nothing') + menu = TerminalMenu(a) + print('Select memory to recall') + index = menu.show() + if index==ind_cancel: + return + self.recall(memory_index=index, **kwargs) + + def _get_elog(self): if hasattr(self, "_elog") and self._elog: diff --git a/eco/endstations/bernina_robots.py b/eco/endstations/bernina_robots.py index bdbe733..d2755c3 100644 --- a/eco/endstations/bernina_robots.py +++ b/eco/endstations/bernina_robots.py @@ -45,6 +45,7 @@ class StaeubliTx200(Assembly): # appending pshell motors motors = [ + ["z_lin", "z_lin", "mm"], ["x", "x", "mm"], ["y", "y", "mm"], ["z", "z", "mm"], @@ -162,7 +163,9 @@ class StaeubliTx200(Assembly): return np.array(sim) def simulate_current_pos(self): - js = np.array([self._cache["pos"][k] for k in ["j1", "j2", "j3", "j4", "j5", "j6"]]) + js = np.array([self._cache["pos"][k] for k in ["z_lin", "j1", "j2", "j3", "j4", "j5", "j6"]]) + if np.any([j is None for j in js]): + raise RobotError("Some of the joint positions are None, check if the connection between server and robot is lost") self._urdf.sim.pos = js self._urdf.sim._ensure_vis_running() self._urdf.sim.vis.step(0) @@ -173,7 +176,10 @@ class StaeubliTx200(Assembly): ######## Helper functions ########## def _auto_updater_simulation(self):# while(True): - js = np.array([self._cache["pos"][k] for k in ["j1", "j2", "j3", "j4", "j5", "j6"]]) + js = np.array([self._cache["pos"][k] for k in ["z_lin", "j1", "j2", "j3", "j4", "j5", "j6"]]) + if np.any([j is None for j in js]): + time.sleep(1) + continue if self.auto_update_simulation(): if not np.all(js == self._urdf.sim.pos): self._urdf.sim.pos = js diff --git a/eco/endstations/bernina_vhamos.py b/eco/endstations/bernina_vhamos.py new file mode 100644 index 0000000..275bea5 --- /dev/null +++ b/eco/endstations/bernina_vhamos.py @@ -0,0 +1,10 @@ +from eco import Assembly +from eco.devices_general.motors import MotorRecord +from eco.detector.jungfrau import Jungfrau + +class VHamos(Assembly): + def __init__(self,name='vhamos',pgroup_adj=None): + super().__init__(name=name) + self._append(MotorRecord,"SARES20-MF1:MOT_8",name="cdist_downstream") + self._append(MotorRecord,"SARES20-MF1:MOT_9",name="cdist_upstream") + self._append(Jungfrau, "JF14T01V01", pgroup_adj=pgroup_adj, name="det_spec") \ No newline at end of file diff --git a/eco/epics/adjustable.py b/eco/epics/adjustable.py index 4800c9f..a5dffc1 100644 --- a/eco/epics/adjustable.py +++ b/eco/epics/adjustable.py @@ -264,13 +264,19 @@ class AdjustablePvEnum: self.pvname = pvname self._pv = PV(pvname, connection_timeout=0.05) self.name = name + self._pv.wait_for_connection() self.enum_strs = self._pv.enum_strs + # while not self.enum_strs: ### HACK to understand gateway slowness + # print(f'could not find enum strs for {self.pvname}') + # time.sleep(.1) + # self.enum_strs = self._pv.enum_strs if pvname_set: self._pv_set = PV(pvname_set, connection_timeout=0.05) tstrs = self._pv_set.enum_strs 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/timing/timetool_online_helper.py b/eco/timing/timetool_online_helper.py index 689664b..917cc53 100644 --- a/eco/timing/timetool_online_helper.py +++ b/eco/timing/timetool_online_helper.py @@ -11,7 +11,8 @@ plt.ion() class TtProcessor: - def __init__(self, Nbg=10): + def __init__(self, Nbg=10, channel_proj = "SARES20-CAMS142-M5.roi_signal_x_profile"): + self.channel_proj = channel_proj self.bg = deque([], Nbg) self.sig = deque([], 1) self.pos = deque([], 1) @@ -19,11 +20,12 @@ class TtProcessor: self.spec_ppd = deque([], 1) self.accumulator = Thread(target=self.run_continuously) self.accumulator.start() + def run_continuously(self): with source( channels=[ - "SARES20-CAMS142-M5.roi_signal_x_profile", + self.channel_proj, "SAR-CVME-TIFALL5:EvtSet", ] ) as s: @@ -31,7 +33,7 @@ class TtProcessor: m = s.receive() ix = m.data.pulse_id - prof = m.data.data["SARES20-CAMS142-M5.roi_signal_x_profile"].value + prof = m.data.data[self.channel_proj].value if prof is None: continue @@ -70,7 +72,9 @@ class TtProcessor: self.lh_sig_last.set_ydata(self.spec_ppd[-1]) return self.lh_sig - def plot_animation(self, name="TT online ana", animate=True): + def plot_animation(self, name=None, animate=True): + if name is None: + name = "TT online ana" + self.channel_proj if len(self.sig) < 1: print("no signals yet") return diff --git a/eco/timing/timing_diag.py b/eco/timing/timing_diag.py index 2c55fbe..ac82fef 100644 --- a/eco/timing/timing_diag.py +++ b/eco/timing/timing_diag.py @@ -1,5 +1,6 @@ from eco.detector.detectors_psi import DetectorBsStream from eco.devices_general.pipelines_swissfel import Pipeline +from eco.microscopes.microscopes import FeturaPlusZoom from ..elements.assembly import Assembly from ..devices_general.motors import SmaractStreamdevice, MotorRecord, SmaractRecord from ..elements.adjustable import AdjustableMemory, AdjustableVirtual @@ -305,3 +306,135 @@ 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 TimetoolSpatial(Assembly): + def __init__( + self, + name=None, + processing_pipeline="SARES20-CAMS142-M4_psen_db", + # edge_finding_pipeline="SAROP21-ATT01_proc", + processing_instance="SARES20-CAMS142-M4_psen_db", + microscope_pvname="SARES20-CAMS142-M4", + delaystage_PV="SARES23-USR:MOT_2", + pvname_target_stage = "SARES20-MF1:MOT_8", + ): + super().__init__(name=name) + + self._append( + MotorRecord, pvname_target_stage, name="transl_target", is_setting=True + ) + + self._append( + SmaractRecord, delaystage_PV, name="delaystage", is_setting=True + ) + self._append(DelayTime, self.delaystage, name="delay", is_setting=True) + + 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.proc_pipeline_edge = edge_finding_pipeline + # self._append(Pipeline,self.proc_pipeline_edge, name='pipeline_edgefinding', is_setting=True) + + + + # self._append( + # MotorRecord, pvname_zoom, name="zoom", is_setting=True, is_display=True + # ) + + self._append( + CameraPCO, + pvname=microscope_pvname, + name="camera_microscope", + camserver_alias=f"{name} ({microscope_pvname})", + is_setting=True, + is_display=False, + ) + + self._append(FeturaPlusZoom,name='zoom') + + + # self._append( + # AdjustablePv, + # pvsetname="SLAAR21-LFEEDBACK1:TARGET1", + # name="feedback_setpoint", + # accuracy=10, + # is_setting=True, + # ) + # self._append( + # AdjustablePv, + # pvsetname="SLAAR21-LFEEDBACK1:ENABLE", + # name="feedback_enabled", + # accuracy=10, + # is_setting=True, + # ) + + self._append( + DetectorBsStream, + "SARES20-CAMS142-M4.roi_signal_x_profile", + cachannel=None, + name="proj_signal", + is_setting=False, + is_display=True, + ) + self._append( + DetectorBsStream, + "SARES20-CAMS142-M4.roi_background_x_prof", + cachannel=None, + name="proj_background", + is_setting=False, + is_display=True, + ) + self._append( + DetectorBsStream, + "SARES20-CAMS142-M5.bsen_signal_x_profile", + cachannel=None, + name="spectrum_bsen", + is_setting=False, + is_display=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(channel_proj="SARES20-CAMS142-M4.roi_signal_x_profile") + + def start_online_monitor(self): + print(f"Starting online data acquisition ...") + self.get_online_data() + print(f"... done, waiting for data coming in ...") + sleep(5) + print(f"... done, starting online plot.") + self.online_monitor.plot_animation() + + # def get_proc_config(self): + # return self.proc_client.get_pipeline_config(self.proc_pipeline) + + # def update_proc_config(self, cfg_dict): + # cfg = self.get_proc_config() + # cfg.update(cfg_dict) + # self.proc_client.set_instance_config(self.proc_instance, cfg) + + # def acquire_and_plot_spectrometer_image(self, N_pulses=50): + # with source(channels=[self.spectrometer_camera_channel]) as s: + # im = [] + # while True: + # m = s.receive() + # tim = m.data.data[self.spectrometer_camera_channel] + # if not tim: + # continue + # if len(im) > N_pulses: + # break + # im.append(tim.value) + # im = np.asarray(im).mean(axis=0) + # fig = plt.figure("bsen spectrometer pattern") + # fig.clf() + # ax = fig.add_subplot(111) + # ax.imshow(im) \ No newline at end of file