#TODO: # currently 2 settings/configs are used # QSettings -> cat ~/.config/Paul\ Scherrer\ Institut/SwissMX.conf # yaml -> swissmx.yaml # QSettings are changed by program # #yaml is fixed and not altened by program import logging _log = logging.getLogger(__name__) from PyQt5.QtCore import QSettings from PyQt5.QtWidgets import QApplication, QMainWindow import json,re import numpy as np class MyJsonEncoder(json.JSONEncoder): """ Special json encoder for numpy types """ def default(self, obj): if isinstance(obj, np.integer): return int(obj) elif isinstance(obj, np.floating): return float(obj) elif isinstance(obj, np.ndarray): return obj.tolist() elif type(obj) not in (dict,list,str,int): _log.error('dont know how to json') return repr(obj) return json.JSONEncoder.default(self, obj) class AppCfg(QSettings): GBL_FLD_SCR_SHOT="global/folder_screenshot" GBL_DEV_PREFIX="global/device_prefix" #SAR-EXPMX GBL_MISC="global/miscellaneous" GEO_OPT_CTR='geometry/opt_ctr' GEO_PIX2POS='geometry/pix2pos' GEO_BEAM_SZ="geometry/beam_size" GEO_BEAM_POS="geometry/beam_pos" GEO_CAM_PARAM="geometry/cam_param" GEO_CAM_TRF="geometry/cam_trf" GEO_FND_FID="geometry/find_fiducial" GEO_AUTOFOC="geometry/autofocus" WINDOW_GEOMETRY="window/geometry" WINDOW_SPLITTER="window/splitter" WINDOW_STATE= "window/state" DFT_POS_DET ="default_position/detector" #json DFT_POS_GONIO ="default_position/gonio" #json DFT_POS_PST ="default_position/post_sample_tube" #json DFT_POS_COL ="default_position/collimator" #json DFT_POS_BKLGT ="default_position/backlight" #json DT_HOST="deltatau/host" DT_MISC="deltatau/miscellaneous" DAQ_DET="daq/detector" #json DAQ_LOC="daq/location" #json DAQ_RUN="daq/run" #json DAQ_BS_CH="daq/bs_channels" #list of str DAQ_PV_CH="daq/pv_channels" #list of str # ---------- OBSOLETE ??? ---------- #ZOOM_BUTTONS="sample_viewing/zoom_buttons" #SKIP_ESCAPE_TRANSITIONS_IF_SAFE="escape/skip_transitions_if_safe" #CRYOJET_MOTION_ENABLED="cryojet/motion_enabled" #CRYOJET_NOZZLE_OUT="cryojet/nozzle_out" #CRYOJET_NOZZLE_IN="cryojet/nozzle_in" #DELTATAU_HOST="deltatau/host" #DELTATAU_SHOW_PLOTS="deltatau/show_plots" #DELTATAU_OMEGACOS="deltatau/omegacos" #DELTATAU_SORT_POINTS="deltatau/sort_points" #DELTATAU_VELOCITY_SCALE="deltatau/velocity_scale" #CAMERA_TRANSFORMATIONS="camera/transformations" #CAMERA_ZOOM_TO_PPM="camera/zoom_to_ppm" #EXPERIMENT_PGROUP="experiment/pgroup" #EXPERIMENT_UID="experiment/uid" #ACTIVATE_PULSE_PICKER="scanning/activate_pulse_picker" def __init__(self): super(AppCfg, self).__init__("PSI", "SwissMX") keys = self.allKeys() # Dump config to debug #for k in keys: # print(k, self.value(k)) #set default keys if not existing dflt=[] if AppCfg.GBL_MISC not in keys: dflt.append((AppCfg.GBL_MISC,{'live_on_collect':False,'img_trace_len':8})) if AppCfg.GBL_DEV_PREFIX not in keys: dflt.append((AppCfg.GBL_DEV_PREFIX, ['SAR-EXPMX','SARES30-ESBMX'])) if AppCfg.GEO_BEAM_SZ not in keys: dflt.append((AppCfg.GEO_BEAM_SZ, [30.2, 25.6])) if AppCfg.GEO_BEAM_POS not in keys: dflt.append((AppCfg.GEO_BEAM_POS, [23.4, 54.2])) if AppCfg.GEO_FND_FID not in keys: dflt.append((AppCfg.GEO_FND_FID, {'sz':101, 'brd':8, 'pitch':120, 'mode':0})) if AppCfg.GEO_AUTOFOC not in keys: dflt.append((AppCfg.GEO_AUTOFOC, {'range':.4, 'velocity':0.3, 'steps':40, 'mode':0})) if AppCfg.GEO_OPT_CTR not in keys: dflt.append((AppCfg.GEO_OPT_CTR, np.array([603.28688025, 520.01112846]) )) if AppCfg.GEO_CAM_TRF not in keys: dflt.append((AppCfg.GEO_CAM_TRF, np.array(((-1, 0, 0), (0, -1, 0), (0, 0, 1))) )) if AppCfg.GEO_PIX2POS not in keys: # rough data z=np.array((1.0, 200.0, 400.0, 600.0, 800.0, 1000.0)) t1=np.array(([1, 0.0000], [0.0000, -1])).reshape(1, -1) #t2=np.array((0.001214,0.000821,0.000495,0.000299,0.000182,0.000108)).reshape(-1, 1) # for binning=1,1 t2=np.array((0.002413,0.001632,0.000994,0.000594,0.000363,0.000205)).reshape(-1, 1) # for binning=2,2 trf=(t1*t2).reshape((-1, 2, 2)) lut_pix2pos=(z, trf) dflt.append((AppCfg.GEO_PIX2POS, lut_pix2pos)) if AppCfg.DT_HOST not in keys: dflt.append((AppCfg.DT_HOST, 'SAR-CPPM-EXPMX1')) if AppCfg.DT_MISC not in keys: dflt.append((AppCfg.DT_MISC,{'show_plots':True, 'vel_scl':1.0, 'fel_per':10.0, 'time_ofs':0.03, 'time_cor':0.0005, 'sync_mode':1, 'sync_flag':3, 'verbose':0xff})) if AppCfg.DAQ_DET not in keys: dflt.append((AppCfg.DAQ_DET, { "name" : "JF17T16V01", "adc_to_energy" : True, "compression" : True, "factor" : 11.33, "geometry" : True, "double_pixels_action" : "mask", "remove_raw_files" : False, "save_dap_results" : True, "crystfel_lists_laser" : True, })) if AppCfg.DAQ_LOC not in keys: dflt.append((AppCfg.DAQ_LOC, {'end_station':"cristallina", 'p_group':"p20516", 'jungfraujoch' : False,})) if AppCfg.DAQ_RUN not in keys: dflt.append((AppCfg.DAQ_RUN, {'prefix':'jf', 'padding':10, 'cell_name' : 'na', 'block_size':1000,})) #if AppCfg.DAQ_BS_CH not in keys: dflt.append((AppCfg.DAQ_BS_CH, ("SARES30-LSCP1-CRISTA1:CH0:1","SAR-CVME-TIFALL6:EvtSet", "SARFE10-PBPG050:PHOTON-ENERGY-PER-PULSE-AVG", "SARFE10-PBIG050-EVR0:CALCI", "SARFE10-PBPG050:HAMP-INTENSITY-CAL", "SARFE10-PBPS053:INTENSITY", "SARFE10-PBPS053:XPOS", "SARFE10-PBPS053:YPOS", "SARFE10-PSSS059:SPECTRUM_X", "SARFE10-PSSS059:SPECTRUM_Y", "SARFE10-PSSS059:SPECTRUM_Y_SUM", "SARFE10-PSSS059:FIT-COM", "SARFE10-PSSS059:FIT-FWHM", "SARFE10-PSSS059:FIT-RES", "SARFE10-PSSS059:FIT-RMS", "SARFE10-PSSS059:FIT_ERR", "SARFE10-PSSS059:SPECT-COM", "SARFE10-PSSS059:SPECT-RES", "SARFE10-PSSS059:SPECT-RMS", "SAROP31-PBPS113:Lnk9Ch0-PP_VAL_PD0", "SAROP31-PBPS113:Lnk9Ch0-PP_VAL_PD1", "SAROP31-PBPS113:Lnk9Ch0-PP_VAL_PD2", "SAROP31-PBPS113:Lnk9Ch0-PP_VAL_PD3", "SAROP31-PBPS113:XPOS", "SAROP31-PBPS113:YPOS", "SAROP31-PBPS113:INTENSITY", "SAROP31-PBPS113:INTENSITY_UJ", "SAROP31-PBPS149:Lnk9Ch0-PP_VAL_PD0", "SAROP31-PBPS149:Lnk9Ch0-PP_VAL_PD1", "SAROP31-PBPS149:Lnk9Ch0-PP_VAL_PD2", "SAROP31-PBPS149:Lnk9Ch0-PP_VAL_PD3", "SAROP31-PBPS149:XPOS", "SAROP31-PBPS149:YPOS", "SAROP31-PBPS149:INTENSITY", "SAROP31-PBPS149:INTENSITY_UJ", "SARES30-LSCP1-FNS:CH7:VAL_GET", "SARES30-LSCP1-FNS:CH6:VAL_GET", "SARES30-LSCP1-FNS:CH5:VAL_GET", "SARES30-LSCP1-FNS:CH4:VAL_GET", "SARES30-LSCP1-FNS:CH3:VAL_GET", "SARES30-LSCP1-FNS:CH2:VAL_GET", "SARES30-LSCP1-FNS:CH1:VAL_GET", "SARES30-LSCP1-FNS:CH0:VAL_GET"))) #list of BS channels #if AppCfg.DAQ_PV_CH not in keys: dflt.append((AppCfg.DAQ_PV_CH, ("SARUN03-UIND030:K_SET.VAL", "SARUN04-UIND030:K_SET.VAL", "SARUN05-UIND030:K_SET.VAL", "SARUN06-UIND030:K_SET.VAL", "SARUN07-UIND030:K_SET.VAL", "SARUN08-UIND030:K_SET.VAL", "SARUN09-UIND030:K_SET.VAL", "SARUN10-UIND030:K_SET.VAL", "SARUN11-UIND030:K_SET.VAL", "SARUN12-UIND030:K_SET.VAL", "SARUN13-UIND030:K_SET.VAL", "SARUN14-UIND030:K_SET.VAL", "SARUN15-UIND030:K_SET.VAL", "SARCL02-MBND100:P-READ", "SARUN:FELPHOTENE.VAL", "SARFE10-PBPG050:PHOTON-ENERGY-PER-PULSE-US", "SARFE10-PBPG050:PHOTON-ENERGY-PER-PULSE-DS", "SARFE10-PBPG050:PHOTON-ENERGY-PER-PULSE-AVG", "SARFE10-OAPU044:MOTOR_X.RBV", "SARFE10-OAPU044:MOTOR_Y.RBV", "SARFE10-OAPU044:MOTOR_W.RBV", "SARFE10-OAPU044:MOTOR_H.RBV", "SAROP31-OAPU107:MOTOR_X.RBV", "SAROP31-OAPU107:MOTOR_Y.RBV", "SAROP31-OAPU107:MOTOR_W.RBV", "SAROP31-OAPU107:MOTOR_H.RBV", "SAROP31-OAPU149:MOTOR_X.RBV", "SAROP31-OAPU149:MOTOR_Y.RBV", "SAROP31-OAPU149:MOTOR_W.RBV", "SAROP31-OAPU149:MOTOR_H.RBV", "SARFE10-OATT053:MOTOR_1.VAL", "SARFE10-OATT053:MOTOR_2.VAL", "SARFE10-OATT053:MOTOR_3.VAL", "SARFE10-OATT053:MOTOR_4.VAL", "SARFE10-OATT053:MOTOR_5.VAL", "SARFE10-OATT053:MOTOR_6.VAL", "SARFE10-OATT053:MOTOR_1.RBV", "SARFE10-OATT053:MOTOR_2.RBV", "SARFE10-OATT053:MOTOR_3.RBV", "SARFE10-OATT053:MOTOR_4.RBV", "SARFE10-OATT053:MOTOR_5.RBV", "SARFE10-OATT053:MOTOR_6.RBV", "SARFE10-OATT053:ENERGY", "SARFE10-OATT053:TRANS_SP", "SARFE10-OATT053:TRANS_RB", "SAROP31-OATA150:MOTOR_1.VAL", "SAROP31-OATA150:MOTOR_2.VAL", "SAROP31-OATA150:MOTOR_3.VAL", "SAROP31-OATA150:MOTOR_4.VAL", "SAROP31-OATA150:MOTOR_5.VAL", "SAROP31-OATA150:MOTOR_6.VAL", "SAROP31-OATA150:MOTOR_1.RBV", "SAROP31-OATA150:MOTOR_2.RBV", "SAROP31-OATA150:MOTOR_3.RBV", "SAROP31-OATA150:MOTOR_4.RBV", "SAROP31-OATA150:MOTOR_5.RBV", "SAROP31-OATA150:MOTOR_6.RBV", "SAROP31-OATA150:ENERGY", "SAROP31-OATA150:TRANS_SP", "SARFE31-OATA150:TRANS_RB", "SARFE10-PBPS053:MOTOR_X1.RBV", "SARFE10-PBPS053:MOTOR_X2.RBV", "SARFE10-PBPS053:MOTOR_PROBE.RBV", "SAROP31-PBPS113:MOTOR_X1.RBV", "SAROP31-PBPS113:MOTOR_Y1.RBV", "SAROP31-PBPS113:MOTOR_PROBE.RBV", "SAROP31-PBPS149:MOTOR_X1.RBV", "SAROP31-PBPS149:MOTOR_Y1.RBV", "SAROP31-PBPS149:MOTOR_PROBE.RBV", "SARFE10-PPRM053:MOTOR_PROBE.RBV", "SAROP31-PSCR068:MOTOR_PROBE.RBV", "SAROP31-PPRM085:MOTOR_PROBE.RBV", "SAROP31-PPRM113:MOTOR_PROBE.RBV", "SAROP31-PPRM150:MOTOR_PROBE.RBV", "SAROP31-PSCD153:MOTOR_PROBE.RBV", "SAROP31-OLAS147:MOTOR_1.RBV", "SAROP31-OPPI151:MOTOR_X1.RBV", "SAROP31-OPPI151:MOTOR_Y1.RBV", "SARFE10-PSSS055:MOTOR_X1.RBV", "SARFE10-PSSS055:MOTOR_Y1.RBV", "SARFE10-PSSS055:MOTOR_ROT_X1.RBV", "SARFE10-PSSS055:MOTOR_PROBE.RBV", "SARFE10-PSSS059:MOTOR_X2.RBV", "SARFE10-PSSS059:MOTOR_X3.RBV", "SARFE10-PSSS059:MOTOR_Y3.RBV", "SARFE10-PSSS059:MOTOR_ROT_X3.RBV", "SARFE10-PSSS059:MOTOR_Y4.RBV", "SARFE10-PSSS059:MOTOR_ROT_X4.RBV", "SARFE10-PSSS059:MOTOR_X5.RBV", "SARFE10-PSSS059:MOTOR_Y5.RBV", "SARFE10-PSSS059:MOTOR_Z5.RBV", "SARFE10-PSSS055:GRATING_SP", "SARFE10-PSSS059:CRYSTAL_SP", "SARFE10-PSSS059:ENERGY", "SARFE10-PSSS059:SPC_ROI_YMIN", "SARFE10-PSSS059:SPC_ROI_YMAX", "SAROP31-OOMH067:W_X.RBV", "SAROP31-OOMH067:W_Y.RBV", "SAROP31-OOMH067:W_RX.RBV", "SAROP31-OOMH067:W_RY.RBV", "SAROP31-OOMH067:W_RZ.RBV", "SAROP31-OOMH067:BU.RBV", "SAROP31-OOMH067:BD.RBV", "SAROP31-OOMH067:VS1.RBV", "SAROP31-OOMH067:VS2.RBV", "SAROP31-OOMH067:VS3.RBV", "SAROP31-OOMH067:TX.RBV", "SAROP31-OOMH067:RY.RBV", "SAROP31-OOMH084:W_X.RBV", "SAROP31-OOMH084:W_Y.RBV", "SAROP31-OOMH084:W_RX.RBV", "SAROP31-OOMH084:W_RY.RBV", "SAROP31-OOMH084:W_RZ.RBV", "SAROP31-OOMH084:BU.RBV", "SAROP31-OOMH084:BD.RBV", "SAROP31-OOMH084:VS1.RBV", "SAROP31-OOMH084:VS2.RBV", "SAROP31-OOMH084:VS3.RBV", "SAROP31-OOMH084:TX.RBV", "SAROP31-OOMH084:RY.RBV", "SAROP31-ODMV152:W_X.RBV", "SAROP31-ODMV152:W_Y.RBV", "SAROP31-ODMV152:W_RX.RBV", "SAROP31-ODMV152:W_RZ.RBV", "SAROP31-ODMV152:BU.RBV", "SAROP31-ODMV152:BD.RBV", "SAROP31-ODMV152:VS1.RBV", "SAROP31-ODMV152:VS2.RBV", "SAROP31-ODMV152:VS3.RBV", "SAROP31-ODMV152:TX.RBV", "SAROP31-OKBV153:W_X.RBV", "SAROP31-OKBV153:W_Y.RBV", "SAROP31-OKBV153:W_RX.RBV", "SAROP31-OKBV153:W_RY.RBV", "SAROP31-OKBV153:W_RZ.RBV", "SAROP31-OKBV153:BU.RBV", "SAROP31-OKBV153:BD.RBV", "SAROP31-OKBV153:TY1.RBV", "SAROP31-OKBV153:TY2.RBV", "SAROP31-OKBV153:TY3.RBV", "SAROP31-OKBV153:TX1.RBV", "SAROP31-OKBV153:TX2.RBV", "", "SAROP31-OKBH154:W_X.RBV", "SAROP31-OKBH154:W_Y.RBV", "SAROP31-OKBH154:W_RX.RBV", "SAROP31-OKBH154:W_RY.RBV", "SAROP31-OKBH154:W_RZ.RBV", "SAROP31-OKBH154:BU.RBV", "SAROP31-OKBH154:BD.RBV", "SAROP31-OKBH154:TY1.RBV", "SAROP31-OKBH154:TY2.RBV", "SAROP31-OKBH154:TY3.RBV", "SAROP31-OKBH154:TX2.RBV") )) #list of PVs if AppCfg.DFT_POS_GONIO not in keys: dflt.append((AppCfg.DFT_POS_GONIO, {'pos_mount':(0.,0.,0.,0.),'pos_align':(0.,0.,0.,0.)}))#default positions if AppCfg.DFT_POS_BKLGT not in keys: dflt.append((AppCfg.DFT_POS_BKLGT, {'pos_in': -30000.0, 'pos_out': 1000.0, 'pos_diode': -30000.0}))#default positions if AppCfg.DFT_POS_PST not in keys: dflt.append((AppCfg.DFT_POS_PST, {'x_in_us': 0.0, 'y_in_us': 0.0, 'x_in_ds': 0.0, 'y_in_ds': 0.0, 'x_out_delta': 0.0, 'y_out_delta': 0.0, 'z_in': 0.0, 'z_out': 0.0}))#default positions for k,v in dflt: _log.warning(f'{k} not defined. use default') self.setValue(k,v) #if AppCfg.ACTIVATE_PULSE_PICKER not in keys: # self.setValue(AppCfg.ACTIVATE_PULSE_PICKER, False) #if AppCfg.SKIP_ESCAPE_TRANSITIONS_IF_SAFE not in keys: # self.setValue(AppCfg.SKIP_ESCAPE_TRANSITIONS_IF_SAFE, False) def sync(self): super(AppCfg, self).sync() def setValue(self, key: str, val): #overload to debug # only simple lists, str, int, float can not be serialized nicely t=type(val) if key in (AppCfg.GEO_PIX2POS,AppCfg.GEO_CAM_TRF): val=json.dumps(val, cls=MyJsonEncoder) elif key in (AppCfg.GBL_MISC, # for all these keys convert to json and change " to ' AppCfg.GEO_CAM_PARAM, AppCfg.GEO_FND_FID, AppCfg.GEO_AUTOFOC, AppCfg.DFT_POS_DET,AppCfg.DFT_POS_GONIO,AppCfg.DFT_POS_PST,AppCfg.DFT_POS_COL,AppCfg.DFT_POS_BKLGT, AppCfg.DT_MISC, AppCfg.DAQ_DET,AppCfg.DAQ_LOC,AppCfg.DAQ_RUN,AppCfg.DAQ_BS_CH,AppCfg.DAQ_PV_CH ): val=json.dumps(val, cls=MyJsonEncoder) val=val.replace('"',"'") elif key in (AppCfg.GEO_OPT_CTR,AppCfg.GEO_BEAM_SZ,AppCfg.GEO_BEAM_POS): if type(val)==np.ndarray: val=val.tolist() elif type(val)==tuple: val=list(val) if type(val)==list: if len(val)==1:val=val[0] elif len(val)==0: val='' return super(AppCfg, self).setValue(key,val) def value(self,key,*vargs,**kwargs): #overload to debug val=super(AppCfg, self).value(key,*vargs,**kwargs) if key in (AppCfg.GEO_PIX2POS,): val=json.loads(val)#, object_hook=MyJsonDecoder) val=(np.array(val[0]),np.array(val[1])) elif key in (AppCfg.GEO_CAM_TRF,): val=json.loads(val)#, object_hook=MyJsonDecoder) val=np.array(val) elif key in (AppCfg.GBL_MISC, AppCfg.GEO_CAM_PARAM, AppCfg.GEO_FND_FID, AppCfg.GEO_AUTOFOC, AppCfg.DFT_POS_DET,AppCfg.DFT_POS_GONIO,AppCfg.DFT_POS_PST,AppCfg.DFT_POS_COL,AppCfg.DFT_POS_BKLGT, AppCfg.DT_MISC, AppCfg.DAQ_DET,AppCfg.DAQ_LOC,AppCfg.DAQ_RUN,AppCfg.DAQ_BS_CH,AppCfg.DAQ_PV_CH ): if val is not None: val=val.replace("'",'"') val=json.loads(val) # , object_hook=MyJsonDecoder) else: val={} elif key in (AppCfg.GEO_BEAM_SZ, AppCfg.GEO_BEAM_POS, AppCfg.GEO_OPT_CTR): val=np.array(tuple(map(float, val))) return val #@property #def value(self): # return super(AppCfg, self).value def option(self,key: str) -> bool: try: return self.value(key, type=bool) except: _log.error(f"option {key} not known") return False def toggle_option(self,key: str): v = self.value(key, type=bool) self.setValue(key, not v) self.sync() from pyqtgraph.parametertree import Parameter, ParameterTree class WndParameter(QMainWindow): def __init__(self, parent=None): super(WndParameter, self).__init__(parent) self.setWindowTitle('SwissMX Preferences') app=QApplication.instance() cfg=app._cfg #GBL_FLD_SCR_SHOT="global/folder_screenshot" #GBL_DEV_PREFIX="global/device_prefix" # SAR-EXPMX #GEO_OPT_CTR #GEO_PIX2POS #GEO_BEAM_POS #GEO_CAM_PARAM gbl_misc = cfg.value(AppCfg.GBL_MISC) gbl_dev_prefix = cfg.value(AppCfg.GBL_DEV_PREFIX) geo_beam_sz = cfg.value(AppCfg.GEO_BEAM_SZ) geo_af = cfg.value(AppCfg.GEO_AUTOFOC) geo_fnd_fid = cfg.value(AppCfg.GEO_FND_FID) dft_pos_pst = cfg.value(AppCfg.DFT_POS_PST) dft_pos_col = cfg.value(AppCfg.DFT_POS_COL) dft_pos_bklgt = cfg.value(AppCfg.DFT_POS_BKLGT) dft_pos_det = cfg.value(AppCfg.DFT_POS_DET) dft_pos_gonio = cfg.value(AppCfg.DFT_POS_GONIO) geo_cam_param = cfg.value(AppCfg.GEO_CAM_PARAM) dt_host = cfg.value(AppCfg.DT_HOST) dt_misc = cfg.value(AppCfg.DT_MISC) daq_det = cfg.value(AppCfg.DAQ_DET) daq_loc = cfg.value(AppCfg.DAQ_LOC) daq_run = cfg.value(AppCfg.DAQ_RUN) tip_sync_mode='''\ default=2 0 : no sync at all 1 : synchronize start 2 : synchronize start and adapt motion speed this function generates the code blocks: self.sync_wait and self.sync_run sync_wait can be put in the program to force a timing sync sync_run are the commands to run the whole program ''' tip_sync_flag='''\ default=0 bit 0=1 : simulated start trigger bit 1=2 : simulated frame trigger 0 : real start and frame trigger 1 : simulated start and real frame trigger 2 : real start and simulated frame trigger 3 : simulated start and frame trigger fel_per : FEL-period: time FEL-pulse to FEL-pulse in ms (needed for sync code) ''' tip_verbose='''\ verbose bits: 0x01 basic info 0x02 plot sorting steps 0x04 list program 0x08 upload progress 0x10 plot gather path 0x20 plot pvt trajectory (before motion) 0x40 print sync details ''' params=[ {'name':'various', 'type':'group','expanded':False, 'children':[ {'name':AppCfg.GBL_DEV_PREFIX, 'title':'device prefix', 'type':'group', 'expanded':False, 'children':[ {'name':'deltatau motors', 'value':gbl_dev_prefix[0], 'type':'str'}, {'name':'smaract motors', 'value':gbl_dev_prefix[1], 'type':'str'}, ]}, {'name':AppCfg.GBL_MISC, 'title':'miscellaneous', 'type':'group', 'children':[ {'name':'live_on_collect', 'value':gbl_misc['live_on_collect'], 'type':'bool','tip':'live view update during collection (may crash if on)'}, {'name':'img_trace_len', 'value':gbl_misc['img_trace_len'], 'type':'int'}, #{'name':'verbose', 'value':gbl_misc['verbose'], 'type':'int', 'tip':tip_verbose}, ]}, # {'name':AppCfg.GEO_CAM_TRF, 'value':cfg.value(AppCfg.GEO_CAM_TRF), 'type':'str'}, ]}, {'name':'geometry','type':'group','expanded':False,'children':[ {'name': AppCfg.GEO_BEAM_SZ, 'title':'size of the beam', 'type':'group', 'children':[ {'name':'width', 'type':'float', 'value':geo_beam_sz[0], 'step':0.1,'suffix':' um'}, {'name':'height', 'type':'float', 'value':geo_beam_sz[1], 'step':0.1,'suffix':' um'}, #{'name':'TEST', 'type':'float', 'value':10.5, 'step':0.001, 'decimals':5}, ]}, {'name':AppCfg.GEO_CAM_TRF, 'value':cfg.value(AppCfg.GEO_CAM_TRF), 'type':'str'}, {'name':AppCfg.GEO_CAM_PARAM, 'title':'camera parameters', 'type':'group', 'expanded':True, 'children':[ {'name':'gain', 'value':geo_cam_param.get('gain'), 'type':'float', 'step':1, }, {'name':'exposure','value':geo_cam_param.get('exposure'),'type':'float', 'step':1, }, {'name':'binning', 'value':geo_cam_param.get('binning'), 'type':'str'}, {'name':'roi', 'value':geo_cam_param.get('roi'), 'type':'str'}, {'name':'mono8', 'value':geo_cam_param.get('mono8'), 'type':'bool'}, ]}, {'name':AppCfg.GEO_FND_FID, 'title':'find fiducial parameters', 'type':'group', 'expanded':True, 'children':[ {'name':'size', 'value':geo_fnd_fid['sz'], 'type':'float', 'step':1, 'suffix':'um'}, {'name':'border', 'value':geo_fnd_fid['brd'], 'type':'float', 'step':1, 'suffix':'um'}, {'name':'pitch', 'value':geo_fnd_fid['pitch'], 'type':'float', 'step':1, 'suffix':'um','tip':'feature not yet used!'}, {'name':'mode', 'value':geo_fnd_fid['mode'], 'type':'int', 'step':1,'tip':'feature not yet used!'}, ]}, {'name':AppCfg.GEO_AUTOFOC, 'title':'autofocus parameters', 'type':'group', 'expanded':True, 'children':[ {'name':'range', 'value':geo_af['range'], 'type':'float', 'limits':(0 ,6 ),'step':0.05,'suffix':'mm','decimals':3,'tip':'autofocus range (-rng/2 mm..+rng/2 mm..'}, {'name':'velocity', 'value':geo_af['velocity'], 'type':'float', 'limits':(0 ,2), 'step':0.05,'suffix':'mm/s','decimals':3}, {'name':'steps', 'value':geo_af['steps'], 'type':'int', 'limits':(0 ,50),'tip':'numbers of measurements in the range'}, {'name':'mode', 'value':geo_af['mode'], 'type':'int', 'step':1,'tip':'feature not yet used!'}, ]}, ]}, {'name': AppCfg.DFT_POS_PST, 'title':'post sample tube reference positions','type':'group','expanded':False,'children':[ {'name':'x_in_us', 'title':'in X upstream', 'value':dft_pos_pst.get('x_in_us' ,0),'type':'float','limits':(-45,17),'step':0.1,'decimals':5,'suffix':' mm'}, {'name':'y_in_us', 'title':'in Y upstream', 'value':dft_pos_pst.get('y_in_us' ,0),'type':'float','limits':(-45,17),'step':0.1,'decimals':5,'suffix':' mm'}, {'name':'x_in_ds', 'title':'in X downstream', 'value':dft_pos_pst.get('x_in_ds' ,0),'type':'float','limits':(-45,17),'step':0.1,'decimals':5,'suffix':' mm'}, {'name':'y_in_ds', 'title':'in Y downstream', 'value':dft_pos_pst.get('y_in_ds' ,0),'type':'float','limits':(-45,17),'step':0.1,'decimals':5,'suffix':' mm'}, {'name':'x_out_delta','title':'out X delta', 'value':dft_pos_pst.get('x_out_delta',0),'type':'float','limits':(-32,32),'step':0.1,'decimals':5,'suffix':' mm'}, {'name':'y_out_delta','title':'out Y delta', 'value':dft_pos_pst.get('y_out_delta',0),'type':'float','limits':(-32,32),'step':0.1,'decimals':5,'suffix':' mm'}, {'name':'z_in', 'title':'in Z', 'value':dft_pos_pst.get('z_in' ,0),'type':'float','limits':(-8 ,5 ),'step':0.1,'decimals':5,'suffix':' mm'}, {'name':'z_out', 'title':'out Z', 'value':dft_pos_pst.get('z_out' ,0),'type':'float','limits':(-8 ,5 ),'step':0.1,'decimals':5,'suffix':' mm'}, {'name':'set_in', 'title':'use current position as "in"', 'type':'action'}, {'name':'set_out', 'title':'use current position as "out"', 'type':'action'}, ]}, {'name': AppCfg.DFT_POS_COL, 'title':'collimator reference positions', 'type':'group','expanded':False, 'children':[ {'name':'x_in', 'title':'in X', 'value':dft_pos_col.get('x_in',0), 'type':'float', 'limits':(-15.9, 15.9 ),'step':0.1, 'decimals':5, 'suffix':' mm'}, {'name':'y_in', 'title':'in Y', 'value':dft_pos_col.get('y_in',0), 'type':'float', 'limits':(-15.9, 15.9 ),'step':0.1, 'decimals':5, 'suffix':' mm'}, {'name':'x_out','title':'out X', 'value':dft_pos_col.get('x_out',0),'type':'float', 'limits':(-15.9, 15.9 ),'step':0.1, 'decimals':5, 'suffix':' mm'}, {'name':'y_out','title':'out Y', 'value':dft_pos_col.get('y_out',0),'type':'float', 'limits':(-15.9, 15.9 ),'step':0.1, 'decimals':5, 'suffix':' mm'}, {'name':'set_in', 'title':'use current position as "in"', 'type':'action'}, {'name':'set_out', 'title':'use current position as "out"', 'type':'action'}, ]}, {'name': AppCfg.DFT_POS_BKLGT, 'title':'Back Light reference positions', 'type':'group','expanded':False, 'children':[ {'name':'pos_in', 'title':'In position', 'value':dft_pos_bklgt.get('pos_in',0), 'type':'float', 'limits':(-31000, 1500 ),'step':10, 'decimals':5, 'suffix':'ustep'}, {'name':'pos_out', 'title':'Out position', 'value':dft_pos_bklgt.get('pos_out',0), 'type':'float', 'limits':(-31000, 1500 ),'step':10, 'decimals':5, 'suffix':'ustep'}, {'name':'pos_diode','title':'Diode pos', 'value':dft_pos_bklgt.get('pos_diode', 0), 'type':'float','limits':(-31000, 1500), 'step':10, 'decimals':5, 'suffix':'ustep'}, ]}, {'name': AppCfg.DFT_POS_DET, 'title':'detector reference positions', 'type':'group','expanded':False, 'children':[ {'name':'pos_in', 'title':'In position', 'value':dft_pos_det.get('pos_in',0), 'type':'float', 'limits':(-200, 200),'step':0.1, 'decimals':5, 'suffix':' mm'}, {'name':'pos_out','title':'Out position', 'value':dft_pos_det.get('pos_out',0), 'type':'float', 'limits':(-200, 200),'step':0.1, 'decimals':5, 'suffix':' mm'}, {'name':'set_in', 'title':'use current position as "in"', 'type':'action'}, {'name':'set_out', 'title':'use current position as "out"', 'type':'action'}, ]}, {'name':AppCfg.DFT_POS_GONIO, 'title':'gonio reference positions', 'type':'group', 'expanded':False, 'children':[ {'name':'pos_mount', 'title':'Mount position', 'value':dft_pos_gonio.get('pos_mount'), 'type':'str' }, {'name':'pos_align', 'title':'Align position', 'value':dft_pos_gonio.get('pos_align'), 'type':'str' }, {'name':'set_mount', 'title':'use current position as "mount"', 'type':'action'}, {'name':'set_align', 'title':'use current position as "align"', 'type':'action'}, ]}, {'name':'Delta Tau Parameters', 'type':'group','expanded':False, 'children':[ {'name':AppCfg.DT_HOST, 'title':'host name (host[:port:port_gather])','value':dt_host, 'type':'str'}, {'name':AppCfg.DT_MISC, 'title':'miscellaneous', 'type':'group', 'children':[ {'name':'show_plots', 'value':dt_misc['show_plots'], 'type':'bool', 'title':'show plots after collection'}, {'name':'vel_scl', 'value':dt_misc['vel_scl'], 'type':'float', 'limits':(0, 1), 'step':0.1, 'title':'velocity_scale', 'tip':"scale between smooth(1.0) and stop and go(0.0)"}, {'name':'fel_per', 'value':dt_misc['fel_per'], 'type':'float', 'step':0.1,'tip':"FEL-period: time FEL-pulse to FEL-pulse in ms"}, {'name':'time_ofs', 'value':dt_misc['time_ofs'], 'type':'float', 'step':0.001,'decimals':4,'tip':"time offset for triggerSync (once)"}, {'name':'time_cor', 'value':dt_misc['time_cor'], 'type':'float', 'step':0.0001,'decimals':5,'tip':"time correction for triggerSync (each frame)"}, {'name':'sync_mode', 'value':dt_misc['sync_mode'], 'type':'int', 'tip':tip_sync_mode}, {'name':'sync_flag', 'value':dt_misc['sync_flag'], 'type':'int', 'tip':tip_sync_flag}, {'name':'verbose', 'value':dt_misc['verbose'], 'type':'int', 'tip':tip_verbose}, ]}, ]}, {'name':'data acquisition', 'type':'group','expanded':False, 'children':[ {'name':AppCfg.DAQ_DET, 'title':'detector', 'type':'group', 'children':[ {'name':'name', 'value':daq_det['name'], 'type':'str',}, {'name':'adc_to_energy', 'value':daq_det['adc_to_energy'], 'type':'bool'}, {'name':'compression', 'value':daq_det['compression'], 'type':'bool'}, {'name':'factor', 'value':daq_det['factor'], 'type':'float','step':0.01}, {'name':'geometry', 'value':daq_det['geometry'], 'type':'bool'}, {'name':'double_pixels_action', 'value':daq_det['double_pixels_action'], 'type':'str'}, {'name':'remove_raw_files', 'value':daq_det['remove_raw_files'], 'type':'bool'}, {'name':'save_dap_results', 'value':daq_det['save_dap_results'], 'type':'bool'}, {'name':'crystfel_lists_laser','value':daq_det['crystfel_lists_laser'],'type':'bool'} ]}, {'name':AppCfg.DAQ_LOC, 'title':'location', 'type':'group', 'children':[ {'name':'end_station', 'value':daq_loc['end_station'], 'type':'str',}, {'name':'p_group', 'value':daq_loc['p_group'], 'type':'str'}, {'name':'jungfraujoch', 'value':daq_loc['jungfraujoch'], 'type':'bool'}, ]}, {'name':AppCfg.DAQ_RUN, 'title':'location', 'type':'group', 'children':[ {'name':'prefix', 'value':daq_run['prefix'], 'type':'str',}, {'name':'padding','value':daq_run['padding'], 'type':'int'}, {'name':'cell_name', 'value':daq_run['cell_name'], 'type':'str'}, {'name':'block_size', 'value':daq_run['block_size'], 'type':'int'}, ]}, {'name':AppCfg.DAQ_BS_CH, 'title':'list of beam-sync channels','value':' '.join(cfg.value(AppCfg.DAQ_BS_CH)), 'type':'str'}, {'name':AppCfg.DAQ_PV_CH, 'title':'list of PV channels','value':' '.join(cfg.value(AppCfg.DAQ_PV_CH)), 'type':'str'}, ]} #{'name':'Save/Restore functionality', 'type':'group','expanded':False, 'children':[ # {'name':'Save State', 'type':'action'}, # {'name':'Restore State', 'type':'action', 'children':[ # {'name':'Add missing items', 'type':'bool', 'value':True}, # {'name':'Remove extra items', 'type':'bool', 'value':True}, # ]}, #]}, ] self._p=p=Parameter.create(name='params', type='group', children=params) p.sigTreeStateChanged.connect(lambda a,b: self.cb_change(a,b)) # Too lazy for recursion: for child in p.children(): child.sigValueChanging.connect(lambda a,b: self.cb_valueChanging(a,b)) for ch2 in child.children(): ch2.sigValueChanging.connect(lambda a,b: self.cb_valueChanging(a,b)) p.param(AppCfg.DFT_POS_PST, 'set_in' ).sigActivated.connect(lambda x: self.cb_use_cur_pos_as(AppCfg.DFT_POS_PST, 'in')) p.param(AppCfg.DFT_POS_PST, 'set_out' ).sigActivated.connect(lambda x: self.cb_use_cur_pos_as(AppCfg.DFT_POS_PST, 'out')) p.param(AppCfg.DFT_POS_COL, 'set_in' ).sigActivated.connect(lambda x: self.cb_use_cur_pos_as(AppCfg.DFT_POS_COL, 'in')) p.param(AppCfg.DFT_POS_COL, 'set_out' ).sigActivated.connect(lambda x: self.cb_use_cur_pos_as(AppCfg.DFT_POS_COL, 'out')) p.param(AppCfg.DFT_POS_DET, 'set_in' ).sigActivated.connect(lambda x: self.cb_use_cur_pos_as(AppCfg.DFT_POS_DET, 'in')) p.param(AppCfg.DFT_POS_DET, 'set_out' ).sigActivated.connect(lambda x: self.cb_use_cur_pos_as(AppCfg.DFT_POS_DET, 'out')) p.param(AppCfg.DFT_POS_GONIO,'set_mount').sigActivated.connect(lambda x: self.cb_use_cur_pos_as(AppCfg.DFT_POS_GONIO,'mount')) p.param(AppCfg.DFT_POS_GONIO,'set_align').sigActivated.connect(lambda x: self.cb_use_cur_pos_as(AppCfg.DFT_POS_GONIO,'align')) #p.param('Save/Restore functionality', 'Save State').sigActivated.connect(self.cb_save) #p.param('Save/Restore functionality', 'Restore State').sigActivated.connect(self.cb_restore) self._paramTree=pt=ParameterTree(parent=self) pt.setParameters(p, showTop=True) pt.setWindowTitle('SwissMX parameters') #t.resize(600, 800) self.setCentralWidget(pt) self.move(100, 100) self.resize(600, 1000) def cb_change(self,paramAll, changes): app=QApplication.instance() cfg=app._cfg assert(self._p==paramAll) #param.parent() for param, change, data in changes: path=paramAll.childPath(param) if path is not None: childName='.'.join(path) else: childName=param.name() _log.debug(f'parameter:{childName} change:{change} data:{str(data)}') parent=param.parent() par_nm=parent.name() nm=param.name() if par_nm in (AppCfg.DAQ_BS_CH, AppCfg.DAQ_PV_CH, AppCfg.DAQ_DET, AppCfg.DAQ_LOC): # this hack must be doneto force a new allocation of a jungfrau object _log.info('delete jungfrau object if existing') try: del app._jungfrau except AttributeError: pass if par_nm==AppCfg.GEO_BEAM_SZ: v = np.array(tuple(map(lambda x: x.value(),parent.children()))) cfg.setValue(par_nm,v) try: bm=self.parent()._goBeamMarker except AttributeError as e: _log.warning('can not set beam size to application window') else: v=v/1000 # convert from um to mm bm.blockSignals(True) # avoid to call cb_marker_moved bm.setSize(v) bm.blockSignals(False) elif par_nm==AppCfg.GEO_CAM_PARAM: d=dict(map(lambda x:(x.name(),x.value()), parent.children())) try: d['roi']=tuple(map(int,re.findall('(?:\d+)',d['roi']))) d['binning']=tuple(map(int,re.findall('(?:\d+)',d['binning']))) except TypeError: _log.warning(f'failed to parse {AppCfg.GEO_CAM_PARAM}:{d}') cfg.setValue(par_nm, d) elif nm == AppCfg.GEO_CAM_TRF: s=param.value() #https://docs.python.org/3/library/re.html#simulating-scanf + no grouping trf=np.array(tuple(map(float,re.findall('[-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][-+]?\d+)?',s)))).reshape(3,3) cfg.setValue(nm,trf) try: grp=self.parent()._goImgGrp except AttributeError as e: _log.warning('can not set transformation to application window') else: tr=QtGui.QTransform() # prepare ImageItem transformation: tr.setMatrix(trf[0, 0], trf[1, 0], trf[2, 0], # (-1, 0, 0, trf[0, 1], trf[1, 1], trf[2, 1], # 0,-1, 0, trf[0, 2], trf[1, 2], trf[2, 2]) # 0, 0, 1) grp.setTransform(tr) # assign transform elif par_nm == AppCfg.DFT_POS_PST: d=dict(map(lambda x:(x.name(),x.value()), parent.children())) for k in ('set_in','set_out'): del d[k] cfg.setValue(par_nm,d) elif par_nm == AppCfg.DFT_POS_COL: d=dict(map(lambda x:(x.name(),x.value()), parent.children())) for k in ('set_in','set_out'): del d[k] cfg.setValue(par_nm,d) elif par_nm == AppCfg.DFT_POS_BKLGT: d=dict(map(lambda x:(x.name(),x.value()), parent.children())) cfg.setValue(par_nm,d) elif par_nm == AppCfg.DFT_POS_DET: d=dict(map(lambda x:(x.name(),x.value()), parent.children())) for k in ('set_in','set_out'): del d[k] cfg.setValue(par_nm,d) elif par_nm == AppCfg.DFT_POS_GONIO: k=parent.children()[:-2] d=dict(map(lambda x:(x.name(),tuple(map(float,x.value().strip('[]()').split(', ')))), k)) cfg.setValue(par_nm,d) elif par_nm==AppCfg.GBL_DEV_PREFIX: v=tuple(map(lambda x:x.value(), parent.children())) cfg.setValue(par_nm, v) elif nm in (AppCfg.DT_HOST): cfg.setValue(nm, param.value()) elif nm in(AppCfg.DAQ_BS_CH,AppCfg.DAQ_PV_CH): s=param.value() lst=s.split(' ') if len(s)>0 else () cfg.setValue(nm,lst) elif par_nm in (AppCfg.GBL_MISC,AppCfg.DT_MISC, AppCfg.GEO_FND_FID,AppCfg.GEO_AUTOFOC, AppCfg.DAQ_DET,AppCfg.DAQ_LOC,AppCfg.DAQ_RUN): d=dict(map(lambda x:(x.name(),x.value()), parent.children())) cfg.setValue(par_nm, d) if par_nm in (AppCfg.GBL_MISC): try: grp=self.parent()._goTrace vb=self.parent().vb except AttributeError as e: _log.warning('can not access the application window') else: grp._tracelen=tl=d['img_trace_len'] cld=grp.childItems() while len(cld)>tl: vb.removeItem(cld[0]) cld=grp.childItems() else: _log.warning(f'can\'t save parameter:{childName} change:{change} data:{str(data)}') raise cfg.sync() def cb_valueChanging(self,param, value): _log.debug(f'Value changing (not finalized): {param}, {value}') def cb_use_cur_pos_as(self,dev,pos): _log.debug(f'HERE {dev}:{pos}') p=self._p.param(dev) try: twk=self.parent().tweakers except AttributeError as e: _log.warning('can not access tweakers to read values') if pos=='in': #sample: just to test p.children()[0].setValue(12.4) elif pos=='out': p.children()[0].setValue(14.1) return #['fast_y', 'fast_x', 'omega', 'base_x', 'base_z', # 'det_z', # 'colli_x', 'colli_y', # 'tube_usx', 'tube_usy', 'tube_dsx', 'tube_dsy', 'tube_z', # 'xeye_x', 'xeye_y']) #p.children() cld=p.children() if dev==AppCfg.DFT_POS_GONIO: if pos=='mount': idx=0 elif pos=='align': idx=1 val=tuple(map(lambda k: twk[k].get_val(),('fast_x','fast_y','base_x','base_z'))) cld[idx].setValue(json.dumps(val, cls=MyJsonEncoder)) return elif dev==AppCfg.DFT_POS_PST: # k=('x_in_us','y_in_us','x_in_ds','y_in_ds','x_out_delta','y_out_delta','z_in','z_out',) if pos=='in': lut=((0,'tube_usx'),(1,'tube_usy'),(2,'tube_dsx'),(3,'tube_dsy'),(6,'tube_z')) elif pos=='out': cld[4].setValue(twk['tube_usx'].get_val()-cld[0].value()) #x_us-x_in_us cld[5].setValue(twk['tube_usy'].get_val()-cld[1].value()) #y_us-y_in_us lut=((7,'tube_z'),) elif dev==AppCfg.DFT_POS_COL: # k=('x_in', 'y_in', 'x_out', 'y_out') if pos=='in': lut=((0,'colli_x'),(1,'colli_y'),) elif pos=='out': lut=((2,'colli_x'),(3,'colli_y'),) elif dev==AppCfg.DFT_POS_DET: if pos=='in': lut=((0,'det_z'),) elif pos=='out': lut=((1,'det_z'),) for i,k in lut: cld[i].setValue(twk[k].get_val()) if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG,format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ') import sys from PyQt5 import QtCore app=QApplication([]) app._cfg=AppCfg() w=WndParameter(None) w.show() ## Start Qt event loop unless running in interactive mode or using pyside. if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): QApplication.instance().exec_()