add DAQ params, better autofocus

This commit is contained in:
2022-09-27 11:11:38 +02:00
parent d8399e901c
commit 30a9c77230
5 changed files with 145 additions and 54 deletions

View File

@@ -58,6 +58,14 @@ class AppCfg(QSettings):
DT_HOST="deltatau/host" DT_HOST="deltatau/host"
DT_MISC="deltatau/miscellaneous" 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 ??? ---------- # ---------- OBSOLETE ??? ----------
#ZOOM_BUTTONS="sample_viewing/zoom_buttons" #ZOOM_BUTTONS="sample_viewing/zoom_buttons"
#SKIP_ESCAPE_TRANSITIONS_IF_SAFE="escape/skip_transitions_if_safe" #SKIP_ESCAPE_TRANSITIONS_IF_SAFE="escape/skip_transitions_if_safe"
@@ -115,6 +123,27 @@ class AppCfg(QSettings):
if AppCfg.DT_MISC not in keys: 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})) 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: for k,v in dflt:
_log.warning(f'{k} not defined. use default') _log.warning(f'{k} not defined. use default')
self.setValue(k,v) self.setValue(k,v)
@@ -136,7 +165,9 @@ class AppCfg(QSettings):
AppCfg.GEO_CAM_PARAM, AppCfg.GEO_CAM_PARAM,
AppCfg.GEO_FND_FID, AppCfg.GEO_AUTOFOC, AppCfg.GEO_FND_FID, AppCfg.GEO_AUTOFOC,
AppCfg.DFT_POS_DET,AppCfg.DFT_POS_PST,AppCfg.DFT_POS_COL,AppCfg.DFT_POS_BKLGT, 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=json.dumps(val, cls=MyJsonEncoder)
val=val.replace('"',"'") val=val.replace('"',"'")
elif key in (AppCfg.GEO_OPT_CTR,AppCfg.GEO_BEAM_SZ,AppCfg.GEO_BEAM_POS): 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() val=val.tolist()
elif type(val)==tuple: elif type(val)==tuple:
val=list(val) 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) return super(AppCfg, self).setValue(key,val)
def value(self,key,*vargs,**kwargs): #overload to debug def value(self,key,*vargs,**kwargs): #overload to debug
@@ -158,13 +192,15 @@ class AppCfg(QSettings):
AppCfg.GEO_CAM_PARAM, AppCfg.GEO_CAM_PARAM,
AppCfg.GEO_FND_FID, AppCfg.GEO_AUTOFOC, AppCfg.GEO_FND_FID, AppCfg.GEO_AUTOFOC,
AppCfg.DFT_POS_DET,AppCfg.DFT_POS_PST,AppCfg.DFT_POS_COL,AppCfg.DFT_POS_BKLGT, 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: if val is not None:
val=val.replace("'",'"') val=val.replace("'",'"')
val=json.loads(val) # , object_hook=MyJsonDecoder) val=json.loads(val) # , object_hook=MyJsonDecoder)
else: else:
val={} 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))) val=np.array(tuple(map(float, val)))
return val return val
@@ -212,6 +248,10 @@ class WndParameter(QMainWindow):
dt_host = cfg.value(AppCfg.DT_HOST) dt_host = cfg.value(AppCfg.DT_HOST)
dt_misc = cfg.value(AppCfg.DT_MISC) 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='''\ tip_sync_mode='''\
default=2 default=2
0 : no sync at all 0 : no sync at all
@@ -328,6 +368,29 @@ verbose bits:
{'name':'verbose', 'value':dt_misc['verbose'], 'type':'int', 'tip':tip_verbose}, {'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/Restore functionality', 'type':'group','expanded':False, 'children':[
# {'name':'Save State', 'type':'action'}, # {'name':'Save State', 'type':'action'},
# {'name':'Restore State', 'type':'action', 'children':[ # {'name':'Restore State', 'type':'action', 'children':[
@@ -430,6 +493,10 @@ verbose bits:
cfg.setValue(par_nm, v) cfg.setValue(par_nm, v)
elif nm in (AppCfg.DT_HOST): elif nm in (AppCfg.DT_HOST):
cfg.setValue(nm, param.value()) 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): 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())) d=dict(map(lambda x:(x.name(),x.value()), parent.children()))
cfg.setValue(par_nm, d) cfg.setValue(par_nm, d)

View File

@@ -447,7 +447,10 @@ class autofocus:
mtr=self._mtr mtr=self._mtr
msk=self._msk msk=self._msk
idx=self._idx 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) img16=np.array(cam._pic, np.int16)
sb1=signal.convolve2d(img16, msk, mode='same', boundary='fill', fillvalue=0) sb1=signal.convolve2d(img16, msk, mode='same', boundary='fill', fillvalue=0)
sb2=signal.convolve2d(img16, msk.T, 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}') _log.debug(f'DONE->{self._idx}')
del cam.process del cam.process
print(mtr[:idx,:]) 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() mx=mtr[:,1].argmax()
self._af=self.interpolate(mtr[:idx,0], mtr[:idx,1]) self._af=self.interpolate(mtr[:idx,0], mtr[:idx,1])
return return

View File

@@ -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 import sys,os,socket
sys.path.insert(0, os.path.expanduser('..')) sys.path.insert(0, os.path.expanduser('..'))
hostname=socket.gethostname() hostname=socket.gethostname()
@@ -8,10 +14,6 @@ else:
sys.path.insert(0, os.path.expanduser("/photonics/home/gac-cristall/Documents/swissmx_cristallina/slic/")) sys.path.insert(0, os.path.expanduser("/photonics/home/gac-cristall/Documents/swissmx_cristallina/slic/"))
#from slic.core.acquisition import SFAcquisition #from slic.core.acquisition import SFAcquisition
import logging
_log=logging.getLogger(__name__)
from PyQt5.QtWidgets import (QApplication,) from PyQt5.QtWidgets import (QApplication,)
from app_config import AppCfg #settings, option, toggle_option from app_config import AppCfg #settings, option, toggle_option
@@ -57,28 +59,17 @@ class Jungfrau:
# -f/sf/cristallina/config/jungfrau/jf_1d5M.json # -f/sf/cristallina/config/jungfrau/jf_1d5M.json
# --start_pulseid 15382163895 --stop_pulseid 15382163905 # --start_pulseid 15382163895 --stop_pulseid 15382163905
#rsync -vai gac-cristall@saresc-cons-03:/sf/jungfrau/applications/daq_client/daq_client.py . #rsync -vai gac-cristall@saresc-cons-03:/sf/jungfrau/applications/daq_client/daq_client.py .
# setup slic parameters # setup slic parameters
detectors = [ { "name" : "JF17T16V01", app=QApplication.instance()
"adc_to_energy" : True, cfg=app._cfg
"compression" : True, detectors = [ cfg.value(AppCfg.DAQ_DET) ]
"factor" : 11.33, bs_channels = cfg.value(AppCfg.DAQ_BS_CH)
"geometry" : True, pv_channels = cfg.value(AppCfg.DAQ_PV_CH)
"double_pixel_action" : "mask", loc=cfg.value(AppCfg.DAQ_LOC)
"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
]
try: try:
self._daq=SFAcquisition( self._daq=SFAcquisition(
"cristallina", "p20516", loc['end_station'], loc['p_group'],
default_detectors=detectors, default_channels=bs_channels, default_pvs=epics_channels, default_detectors=detectors, default_channels=bs_channels, default_pvs=pv_channels,
rate_multiplicator=1, append_user_tag_to_data_dir=True rate_multiplicator=1, append_user_tag_to_data_dir=True
) )
except NameError as e: 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=epics.PV('SAR-EXPMX-EVR0:RX-PULSEID')
self._pv_pulse_id.connect() 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) self._pulse_id_start=int(self._pv_pulse_id.value)
if self._daq is not None: 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 pass
run['id']+=1
cfg.setValue(AppCfg.DAQ_RUN,run)
def gather_upload(self): def gather_upload(self):
self._pulse_id_end=int(self._pv_pulse_id.value) self._pulse_id_end=int(self._pv_pulse_id.value)
_log.debug(f'pulse_id: {self._pulse_id_start}..{self._pulse_id_end}') _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()

View File

@@ -66,11 +66,30 @@ def obj_info(obj,p=''):
except AttributeError: except AttributeError:
pass 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.""" """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): def __init__(self, pos, size, mode, **kargs):
pg.ROI.__init__(self, pos, size, **kargs) UsrROI.__init__(self, pos, size, **kargs)
self._mode=mode self._mode=mode
#widget.signal.connect(slot_function) #widget.signal.connect(slot_function)
#self.sigRegionChangeFinished.connect(self.OnRgnChanged) #self.sigRegionChangeFinished.connect(self.OnRgnChanged)
@@ -147,24 +166,6 @@ class Marker(pg.ROI):
p.setTransform(tr) p.setTransform(tr)
return ofx,ofy 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): class Fiducial(UsrROI):
def __init__(self, pos, size, z:float, **kargs): def __init__(self, pos, size, z:float, **kargs):

View File

@@ -370,7 +370,7 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
#--- opctical center ---- #--- opctical center ----
oc_sz=np.array((50,50)) 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) self._goOptCtr=obj=UsrGO.Marker(opt_ctr-oc_sz/2, oc_sz,mode=1, movable=False)
obj.sigRegionChangeFinished.connect(self.cb_marker_moved) obj.sigRegionChangeFinished.connect(self.cb_marker_moved)
grp.addItem(obj) grp.addItem(obj)
@@ -407,14 +407,12 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
#--- beam marker --- #--- beam marker ---
size_eu=cfg.value(AppCfg.GEO_BEAM_SZ)/1000 # convert from um to mm 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 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) obj.sigRegionChangeFinished.connect(self.cb_marker_moved)
#bm.setTransform(tr) # assign transform #bm.setTransform(tr) # assign transform
grp.addItem(obj) grp.addItem(obj)
#--- testing scan grid --- #--- testing scan grid ---
#self.track_objects() # first call is needed to initialize the structure self._goTracked #self.track_objects() # first call is needed to initialize the structure self._goTracked
# #go=UsrGO.Grid((120, -100), (200, 150), (30, 22), 2) # #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.wait_armed() # wait until motors are at first position
sp.trigger(0.5) # send a start trigger (if needed) after given time 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: if not dt._comm is None:
dlg.setLabelText("run motion/acquisition") dlg.setLabelText("run motion/acquisition")
dlg.setMaximum(sp.points.shape[0]) dlg.setMaximum(sp.points.shape[0])