diff --git a/app_config.py b/app_config.py index 7cda7b2..99a0029 100644 --- a/app_config.py +++ b/app_config.py @@ -58,6 +58,14 @@ class AppCfg(QSettings): 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" @@ -115,6 +123,27 @@ class AppCfg(QSettings): if AppCfg.DT_MISC not in keys: dflt.append((AppCfg.DT_MISC,{'show_plots':True, 'vel_scl':1.0, 'pt2pt_time':10.0, '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_pixel_action" : "mask", + "remove_raw_files" : False + })) + if AppCfg.DAQ_LOC not in keys: + dflt.append((AppCfg.DAQ_LOC, {'end_station':"cristallina", 'p_group':"p20516"})) + if AppCfg.DAQ_RUN not in keys: + dflt.append((AppCfg.DAQ_RUN, {'prefix':'', 'id':0})) + if AppCfg.DAQ_BS_CH not in keys: + dflt.append((AppCfg.DAQ_BS_CH, ("SARES30-LSCP1-CRISTA1:CH0:1",))) #list of BS channels + if AppCfg.DAQ_PV_CH not in keys: + dflt.append((AppCfg.DAQ_PV_CH, () )) #list of PVs + + + for k,v in dflt: _log.warning(f'{k} not defined. use default') self.setValue(k,v) @@ -136,7 +165,9 @@ class AppCfg(QSettings): AppCfg.GEO_CAM_PARAM, AppCfg.GEO_FND_FID, AppCfg.GEO_AUTOFOC, AppCfg.DFT_POS_DET,AppCfg.DFT_POS_PST,AppCfg.DFT_POS_COL,AppCfg.DFT_POS_BKLGT, - AppCfg.DT_MISC): + 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): @@ -144,6 +175,9 @@ class AppCfg(QSettings): 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 @@ -158,13 +192,15 @@ class AppCfg(QSettings): AppCfg.GEO_CAM_PARAM, AppCfg.GEO_FND_FID, AppCfg.GEO_AUTOFOC, AppCfg.DFT_POS_DET,AppCfg.DFT_POS_PST,AppCfg.DFT_POS_COL,AppCfg.DFT_POS_BKLGT, - AppCfg.DT_MISC): + 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): + elif key in (AppCfg.GEO_BEAM_SZ, AppCfg.GEO_BEAM_POS, AppCfg.GEO_OPT_CTR): val=np.array(tuple(map(float, val))) return val @@ -212,6 +248,10 @@ class WndParameter(QMainWindow): 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 @@ -328,6 +368,29 @@ verbose bits: {'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_pixel_action', 'value':daq_det['double_pixel_action'], 'type':'str'}, + {'name':'remove_raw_files', 'value':daq_det['remove_raw_files'], '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':AppCfg.DAQ_RUN, 'title':'location', 'type':'group', 'children':[ + {'name':'prefix', 'value':daq_run['prefix'], 'type':'str',}, + {'name':'id', 'value':daq_run['id'], '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':[ @@ -430,6 +493,10 @@ verbose bits: 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): d=dict(map(lambda x:(x.name(),x.value()), parent.children())) cfg.setValue(par_nm, d) diff --git a/geometry.py b/geometry.py index 2f7e362..5834878 100755 --- a/geometry.py +++ b/geometry.py @@ -447,7 +447,10 @@ class autofocus: mtr=self._mtr msk=self._msk idx=self._idx - p=mot.get_rbv() + p=mot.get_rbv() # the position is only polled at slow rate. + # ŧherefore the received positions are sometimes the same + # could try direct deltatau communications + img16=np.array(cam._pic, np.int16) sb1=signal.convolve2d(img16, msk, mode='same', boundary='fill', fillvalue=0) sb2=signal.convolve2d(img16, msk.T, mode='same', boundary='fill', fillvalue=0) @@ -460,6 +463,8 @@ class autofocus: _log.debug(f'DONE->{self._idx}') del cam.process print(mtr[:idx,:]) + mtr[:idx,0]=np.linspace(mtr[0,0],mtr[idx-1,0],idx) # smoothing the positions with equally spaced distances + print(mtr[:idx,:]) mx=mtr[:,1].argmax() self._af=self.interpolate(mtr[:idx,0], mtr[:idx,1]) return diff --git a/psi_device.py b/psi_device.py index 983b6a5..fbba378 100644 --- a/psi_device.py +++ b/psi_device.py @@ -1,3 +1,9 @@ +import logging +_log=logging.getLogger(__name__) +if __name__ == "__main__": + logging.basicConfig(level=logging.DEBUG,format='%(name)s:%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ') + logging.getLogger('matplotlib').setLevel(logging.INFO) + import sys,os,socket sys.path.insert(0, os.path.expanduser('..')) hostname=socket.gethostname() @@ -8,10 +14,6 @@ else: sys.path.insert(0, os.path.expanduser("/photonics/home/gac-cristall/Documents/swissmx_cristallina/slic/")) #from slic.core.acquisition import SFAcquisition - -import logging -_log=logging.getLogger(__name__) - from PyQt5.QtWidgets import (QApplication,) from app_config import AppCfg #settings, option, toggle_option @@ -57,28 +59,17 @@ class Jungfrau: # -f/sf/cristallina/config/jungfrau/jf_1d5M.json # --start_pulseid 15382163895 --stop_pulseid 15382163905 #rsync -vai gac-cristall@saresc-cons-03:/sf/jungfrau/applications/daq_client/daq_client.py . - - # setup slic parameters - detectors = [ { "name" : "JF17T16V01", - "adc_to_energy" : True, - "compression" : True, - "factor" : 11.33, - "geometry" : True, - "double_pixel_action" : "mask", - "remove_raw_files" : False - } ] #["JF17T16V01"] - bs_channels = [ # have timing signitures - "SARES30-LSCP1-CRISTA1:CH0:1", - # "SARES30-CAMS156-SMX-OAV:FPICTURE" - ] - epics_channels = [ # no time signitures - ] - + app=QApplication.instance() + cfg=app._cfg + detectors = [ cfg.value(AppCfg.DAQ_DET) ] + bs_channels = cfg.value(AppCfg.DAQ_BS_CH) + pv_channels = cfg.value(AppCfg.DAQ_PV_CH) + loc=cfg.value(AppCfg.DAQ_LOC) try: self._daq=SFAcquisition( - "cristallina", "p20516", - default_detectors=detectors, default_channels=bs_channels, default_pvs=epics_channels, + loc['end_station'], loc['p_group'], + default_detectors=detectors, default_channels=bs_channels, default_pvs=pv_channels, rate_multiplicator=1, append_user_tag_to_data_dir=True ) except NameError as e: @@ -87,14 +78,43 @@ class Jungfrau: self._pv_pulse_id=epics.PV('SAR-EXPMX-EVR0:RX-PULSEID') self._pv_pulse_id.connect() - def acquire(self,run_name, n_pulses, wait=False): + def acquire(self, n_pulses, wait=False): + app=QApplication.instance() + cfg=app._cfg + run=cfg.value(AppCfg.DAQ_RUN) self._pulse_id_start=int(self._pv_pulse_id.value) if self._daq is not None: - self._daq.acquire(run_name, n_pulses=n_pulses, wait=False) + self._daq.acquire(run['prefix'], n_pulses=n_pulses, wait=False) pass + run['id']+=1 + cfg.setValue(AppCfg.DAQ_RUN,run) def gather_upload(self): self._pulse_id_end=int(self._pv_pulse_id.value) _log.debug(f'pulse_id: {self._pulse_id_start}..{self._pulse_id_end}') +if __name__ == "__main__": + import os + import argparse + if hostname=='ganymede': + # use EPICS locally + # os.environ['EPICS_CA_ADDR_LIST']='localhost' + # use EPICS if connected to ESC network + os.environ['EPICS_CA_ADDR_LIST']='129.129.244.255 sf-saresc-cagw.psi.ch:5062 sf-saresc-cagw.psi.ch:5066' + + parser = argparse.ArgumentParser() + parser.add_argument("--mode", "-m", help="qt test", type=lambda x:int(x, 0), default=0) + args = parser.parse_args() + + _log.info('Arguments:{}'.format(args.__dict__)) + app=QApplication(sys.argv) + app._cfg=cfg=AppCfg() + + if args.mode &0x01: + dt=Deltatau() + if args.mode&0x02: + jf=Jungfrau() + jf.acquire(n_pulses=100, wait=True) + jf.gather_upload() + diff --git a/pyqtUsrObj.py b/pyqtUsrObj.py index f0e327b..2011e41 100644 --- a/pyqtUsrObj.py +++ b/pyqtUsrObj.py @@ -66,11 +66,30 @@ def obj_info(obj,p=''): except AttributeError: pass -class Marker(pg.ROI): +class UsrROI(pg.ROI): + def __init__(self, pos, size, **kargs): + pg.ROI.__init__(self, pos, size, **kargs) + + def cb_toggle_movable(self): + self.translatable=not self.translatable + + def contextMenuEvent(self, event): + #pg.ROI.contextMenuEvent(self,event) + _log.debug('ContextMenu') + menu = QMenu("ctx") + act=menu.addAction('locked') + act.setCheckable(True) + act.setChecked(not self.translatable) + act.triggered.connect(self.cb_toggle_movable) + #menu.addAction('center in view') + #menu.addAction('delete') + menu.exec(event.screenPos()) + +class Marker(UsrROI): """A crosshair ROI whose position is at the center of the crosshairs. By default, it is scalable, rotatable and translatable.""" def __init__(self, pos, size, mode, **kargs): - pg.ROI.__init__(self, pos, size, **kargs) + UsrROI.__init__(self, pos, size, **kargs) self._mode=mode #widget.signal.connect(slot_function) #self.sigRegionChangeFinished.connect(self.OnRgnChanged) @@ -147,24 +166,6 @@ class Marker(pg.ROI): p.setTransform(tr) return ofx,ofy -class UsrROI(pg.ROI): - def __init__(self, pos, size, **kargs): - pg.ROI.__init__(self, pos, size, **kargs) - - def cb_toggle_movable(self): - self.translatable=not self.translatable - - def contextMenuEvent(self, event): - #pg.ROI.contextMenuEvent(self,event) - _log.debug('ContextMenu') - menu = QMenu("ctx") - act=menu.addAction('locked') - act.setCheckable(True) - act.setChecked(not self.translatable) - act.triggered.connect(self.cb_toggle_movable) - #menu.addAction('center in view') - #menu.addAction('delete') - menu.exec(event.screenPos()) class Fiducial(UsrROI): def __init__(self, pos, size, z:float, **kargs): diff --git a/swissmx.py b/swissmx.py index c6a094f..43bda59 100755 --- a/swissmx.py +++ b/swissmx.py @@ -370,7 +370,7 @@ class WndSwissMx(QMainWindow, Ui_MainWindow): #--- opctical center ---- oc_sz=np.array((50,50)) #self._goOptCtr=obj=UsrGO.Marker(-opt_ctr+oc_sz/2, oc_sz,mode=1) - self._goOptCtr=obj=UsrGO.Marker(opt_ctr-oc_sz/2, oc_sz,mode=1) + self._goOptCtr=obj=UsrGO.Marker(opt_ctr-oc_sz/2, oc_sz,mode=1, movable=False) obj.sigRegionChangeFinished.connect(self.cb_marker_moved) grp.addItem(obj) @@ -407,14 +407,12 @@ class WndSwissMx(QMainWindow, Ui_MainWindow): #--- beam marker --- size_eu=cfg.value(AppCfg.GEO_BEAM_SZ)/1000 # convert from um to mm pos_eu=cfg.value(AppCfg.GEO_BEAM_POS)/1000 # convert from um to mm - self._goBeamMarker=obj=UsrGO.Marker(pos_eu-size_eu/2,size_eu,mode=0) + self._goBeamMarker=obj=UsrGO.Marker(pos_eu-size_eu/2,size_eu,mode=0,movable=False) obj.sigRegionChangeFinished.connect(self.cb_marker_moved) #bm.setTransform(tr) # assign transform grp.addItem(obj) - - #--- testing scan grid --- #self.track_objects() # first call is needed to initialize the structure self._goTracked # #go=UsrGO.Grid((120, -100), (200, 150), (30, 22), 2) @@ -2154,7 +2152,7 @@ Author Thierry Zamofing (thierry.zamofing@psi.ch) sp.wait_armed() # wait until motors are at first position sp.trigger(0.5) # send a start trigger (if needed) after given time - jf.acquire('filename.tmp',sp.points.shape[0]) + jf.acquire(sp.points.shape[0]) if not dt._comm is None: dlg.setLabelText("run motion/acquisition") dlg.setMaximum(sp.points.shape[0])