From 6efb6e38c79d2b024efdd3e18661ff5226ecd96f Mon Sep 17 00:00:00 2001 From: Roman Mankowsky Date: Fri, 13 Nov 2020 16:16:49 +0100 Subject: [PATCH] added automatic threaded upload of the run_table to gsheet, whenever a position is recorded --- eco/bernina/bernina.py | 18 ++ eco/bernina/config.py | 24 +- eco/detector/jungfrau.py | 8 +- eco/endstations/bernina_diffractometers.py | 28 ++- eco/utilities/runtable.py | 18 +- eco/xoptics/kb_bernina.py | 245 +++++++++++++++++---- 6 files changed, 285 insertions(+), 56 deletions(-) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index 3157116..827f571 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -3,4 +3,22 @@ import sys from .config import config + # { + # "name": "elog", + # "type": "eco.utilities.elog:Elog", + # "args": ["https://elog-gfa.psi.ch/Bernina"], + # "kwargs": { + # "screenshot_directory": "/tmp", + # }, + # }, + + +@init_obj(lazy=is_globally_lazy) +def init_specific_device(*args,**kwargs): + from whatever import something + return something(*args,**kwargs) +specific_name = init_specific_device(name=specific_name) + + + diff --git a/eco/bernina/config.py b/eco/bernina/config.py index 3da6bd6..78906b8 100755 --- a/eco/bernina/config.py +++ b/eco/bernina/config.py @@ -51,7 +51,7 @@ components = [ "alias_namespace": None, "channels_ca": Component("_env_channels_ca"), }, - "lazy": False, + "lazy": True, }, { "type": "eco.elements.memory:set_global_memory_dir", @@ -359,15 +359,15 @@ components = [ "type": "eco.xoptics.KBhor:KBhor", "kwargs": {}, }, - { - "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": False, - }, + # { + # "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": [], @@ -388,7 +388,7 @@ components = [ "configuration": config["gps_config"], "fina_hex_angle_offset": "~/eco/reference_values/hex_pi_angle_offset.json", }, - "lazy": False, + "lazy": True, }, { "args": [], @@ -409,7 +409,7 @@ components = [ "configuration": config["xrd_config"], "diff_detector": {"jf_id": "JF01T03V01"}, }, - "lazy": False, + "lazy": True, }, { "args": [], diff --git a/eco/detector/jungfrau.py b/eco/detector/jungfrau.py index 83ff1b0..71d486e 100644 --- a/eco/detector/jungfrau.py +++ b/eco/detector/jungfrau.py @@ -22,7 +22,9 @@ class Jungfrau(Assembly): self.memory = memory.Memory(self) self.jf_id = jf_id - self._append(PvRecord, pv_trigger, is_status=True, name="trigger") + self._append( + PvRecord, pv_trigger, is_status=True, is_setting=False, name="trigger" + ) self._trigger_on = trigger_on self._trigger_off = trigger_off self._append( @@ -32,11 +34,11 @@ class Jungfrau(Assembly): self._set_trigger_enable, name="trigger_enable", append_aliases=False, - is_setting=True, + is_setting=False, ) def _set_trigger_enable(self, value): if value: self.trigger.set_target_value(self._trigger_on).wait() else: - self.trigger.set_target_value(self._triggeroff).wait() + self.trigger.set_target_value(self._trigger_off).wait() diff --git a/eco/endstations/bernina_diffractometers.py b/eco/endstations/bernina_diffractometers.py index 189fc6a..f7915b7 100644 --- a/eco/endstations/bernina_diffractometers.py +++ b/eco/endstations/bernina_diffractometers.py @@ -89,6 +89,18 @@ class GPS: return self.get_adjustable_positions_str() +class DeltaTauCurrOff: + def __init__(self, pvname, name=None): + self.pvname = pvname + self.PV = PV(pvname) + + def set_off(self): + self.PV.put("#1..8k") + + def __call__(self): + self.set_off() + + class XRD(Assembly): def __init__(self, name=None, Id=None, configuration=["base"], diff_detector=None): """X-ray diffractometer platform in AiwssFEL Bernina.\ @@ -109,6 +121,7 @@ class XRD(Assembly): self._append( MotorRecord_new, Id + ":MOT_MY_RYTH", name="alpha", is_setting=True ) + self.set_base_off = DeltaTauCurrOff("SARES21-XRD:asyn4.AOUT") if "arm" in self.configuration: ### motors XRD detector arm ### @@ -124,6 +137,7 @@ class XRD(Assembly): ### motors XRD polarisation analyzer branch ### self._append(MotorRecord_new, Id + ":MOT_P_T", name="tpol", is_setting=True) # missing: slits of flight tube + self.set_detarm_off = DeltaTauCurrOff("SARES21-XRD:asyn3.AOUT") if "hlxz" in self.configuration: ### motors heavy load goniometer ### @@ -133,10 +147,12 @@ class XRD(Assembly): self._append( MotorRecord_new, Id + ":MOT_TBL_TZ", name="zhl", is_setting=True ) + self.set_phi_off = DeltaTauCurrOff("SARES21-XRD:asyn1.AOUT") if "hly" in self.configuration: self._append( MotorRecord_new, Id + ":MOT_TBL_TY", name="yhl", is_setting=True ) + self.set_phi_off = DeltaTauCurrOff("SARES21-XRD:asyn1.AOUT") if "hlrxrz" in self.configuration: try: @@ -152,7 +168,7 @@ class XRD(Assembly): ) except: print("XRD.rzhl not found") - pass + self.set_phi_off = DeltaTauCurrOff("SARES21-XRD:asyn1.AOUT") if "phi_table" in self.configuration: ### motors nu table ### @@ -242,8 +258,16 @@ class XRD(Assembly): name="rykap", is_setting=True, ) + self.set_kappa_off = DeltaTauCurrOff("SARES21-XRD:asyn1.AOUT") if diff_detector: - self._append(Jungfrau, diff_detector["jf_id"], name="det_diff") + self._append( + Jungfrau, + diff_detector["jf_id"], + name="det_diff", + is_setting=False, + is_status=True, + view_toplevel_only=True, + ) def get_adjustable_positions_str(self): ostr = "*****XRD motor positions******\n" diff --git a/eco/utilities/runtable.py b/eco/utilities/runtable.py index ebfaaae..27df246 100644 --- a/eco/utilities/runtable.py +++ b/eco/utilities/runtable.py @@ -16,6 +16,8 @@ import xlwt import openpyxl from ..devices_general.pv_adjustable import PvRecord from epics import caget +import threading + class Run_Table(): def __init__(self, pgroup=None,spreadsheet_key=None, devices=None, alias_namespace=None, channels_ca={'pulse_id': 'SLAAR11-LTIM01-EVR0:RX-PULSEID'}, name=None): @@ -147,8 +149,8 @@ class Run_Table(): 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.save() + self.upload_all() def append_pos(self, name=''): self.load() @@ -175,6 +177,7 @@ class Run_Table(): 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): ''' @@ -222,6 +225,17 @@ class Run_Table(): 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(' ') diff --git a/eco/xoptics/kb_bernina.py b/eco/xoptics/kb_bernina.py index 9bf0622..d35aeb0 100644 --- a/eco/xoptics/kb_bernina.py +++ b/eco/xoptics/kb_bernina.py @@ -1,8 +1,24 @@ import numpy as np from scipy import constants +from ..elements import Assembly +from ..devices_general.motors import MotorRecord +from ..devices_general.adjustable import PvRecord + class KBMirrorBernina: - def __init__(self,kb_ver=None, kb_hor=None, usd_table=None, d_kbver=3350.,d_kbhor=2600.,d_hex=1600.,d_win1=1945.,d_win2=1330.,d_target=1520.,d_att=1420.): + 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 @@ -15,62 +31,217 @@ class KBMirrorBernina: self.d_win1 = d_win1 self.d_target = d_target - def calc_positions(self,the_kbver,the_kbhor): + 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) + 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} + 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): + 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 + 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 + 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 + 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) + 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["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. - 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": + 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) + self.usd_table.move_to_coordinates(x, y, z, rx, ry, rz) +class KBMirrorBernina_new(Assembly): + def __init__( + self, + pvname_hor, + pvname_ver, + 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""" + super().__init__(name=name) + 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 + self._add(MotorRecord, pvname_hor + ":W_X", name="x_hor") + self._add(MotorRecord, pvname_hor + ":W_Y", name="y_hor") + self._add(MotorRecord, pvname_hor + ":W_RY", name="y_hor") + self._add(MotorRecord, pvname_hor + ":W_RY", name="pitch_hor") + self._add(MotorRecord, pvname_hor + ":W_RZ", name="roll_hor") + self._add(MotorRecord, pvname_hor + ":W_RX", name="yaw_hor") + self._add(MotorRecord, pvname_hor + ":BU", name="bend_upstream_hor") + self._add(MotorRecord, pvname_hor + ":BD", name="bend_downstream_hor") + self._add(MotorRecord, pvname_hor + ":TY1", name="y1_phys_hor") + self._add(MotorRecord, pvname_hor + ":TY2", name="y2_phys_hor") + self._add(MotorRecord, pvname_hor + ":TY3", name="y3_phys_hor") + self._add(MotorRecord, pvname_hor + ":TX1", name="x1_phys_hor") + self._add(MotorRecord, pvname_hor + ":TX2", name="x2_phys_hor") - + self._add( + PvRecord, + pvsetname=Id + ":CURV_SP", + pvreadbackname=Id + ":CURV", + accuracy=0.002, + name="curv", + ) + addPvRecordToSelf( + self, + pvsetname=Id + ":ASYMMETRY_SP", + pvreadbackname=Id + ":ASYMMETRY", + accuracy=0.002, + name="asym", + ) + + 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)