270 lines
11 KiB
Python
270 lines
11 KiB
Python
import logging,sys,os,socket
|
|
|
|
from math import ceil
|
|
_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)
|
|
|
|
if socket.gethostname()=='ganymede':
|
|
sys.path.insert(0, os.path.expanduser('~/Documents/prj/SwissFEL/PBTools'))
|
|
else:
|
|
sys.path.insert(0, '/sf/cristallina/applications/SwissMX/PBTools')
|
|
sys.path.insert(0, '/sf/cristallina/applications/SwissMX/PBSwissMX/python')
|
|
#_log.info(sys.path)
|
|
elif socket.gethostname()!='ganymede':
|
|
#TODO: cleanup slic installation location
|
|
sys.path.insert(0, os.path.expanduser('/sf/cristallina/applications/mx/slic'))
|
|
#sys.path.insert(0, os.path.expanduser('/sf/cristallina/applications/slic/slic-package'))
|
|
|
|
|
|
|
|
from PyQt5.QtWidgets import (QApplication,)
|
|
from app_config import AppCfg #settings, option, toggle_option
|
|
|
|
import epics
|
|
from pbtools.misc.pp_comm import PPComm
|
|
from pbtools.misc.gather import Gather
|
|
import shapepath
|
|
|
|
try:
|
|
from slic.core.acquisition import SFAcquisition
|
|
from slic.devices.timing.events import CTASequencer
|
|
from ctadaq import CTAAcquisition
|
|
from jfjoch_device import JFJ
|
|
except ImportError as e:
|
|
_log.warning(e)
|
|
|
|
class Shutter:
|
|
|
|
def __init__(self,mode=1):
|
|
self._mode=mode
|
|
app=QApplication.instance() #apologies! Wasn't sure how best to do this, could maybe feed sync_flag as a variable to open and close from swissmx.py
|
|
cfg=app._cfg
|
|
dt_misc = cfg.value(AppCfg.DT_MISC)
|
|
self.sync_flag=dt_misc['sync_flag']
|
|
|
|
def open(self):
|
|
mode=self._mode
|
|
if mode==0:
|
|
_log.info('open simulated shutter')
|
|
elif mode==1:
|
|
# open laser shutter
|
|
epics.caput("SLAAR31-LPSYS-ESC:LHX1_SHUT_OPEN", 1)
|
|
if self.sync_flag==0: #if using cta, sets pulse_picker output to follow pulser 3
|
|
# open fast shutter
|
|
epics.caput("SARES30-LTIM01-EVR0:RearUniv0_SNUMPD", 3)
|
|
epics.caput("SARES30-LTIM01-EVR0:RearUniv0_SNUMPD2", 3)
|
|
epics.caput("SARES30-LTIM01-EVR0:RearUniv0_SOURCE", 0)
|
|
epics.caput("SARES30-LTIM01-EVR0:RearUniv0_SOURCE2", 0)
|
|
epics.caput("SARES30-LTIM01-EVR0:RearUniv0-Ena-SP", 1)
|
|
_log.info('shutter opened')
|
|
|
|
def close(self):
|
|
mode=self._mode
|
|
if mode==0:
|
|
_log.info('close simulated shutter')
|
|
elif mode==1:
|
|
|
|
# close laser shutter
|
|
epics.caput("SLAAR31-LPSYS-ESC:LHX1_SHUT_CLOSE", 1)
|
|
_log.info('shutter closed')
|
|
|
|
# close fast shutter
|
|
epics.caput("SARES30-LTIM01-EVR0:RearUniv0-Ena-SP", 0)
|
|
if self.sync_flag==0: #if using cta, sets pulse_picker output back to high low, could do this every time?
|
|
epics.caput("SARES30-LTIM01-EVR0:RearUniv0_SNUMPD", 1)
|
|
epics.caput("SARES30-LTIM01-EVR0:RearUniv0_SNUMPD2", 1)
|
|
epics.caput("SARES30-LTIM01-EVR0:RearUniv0_SOURCE", 3)
|
|
epics.caput("SARES30-LTIM01-EVR0:RearUniv0_SOURCE2", 4)
|
|
|
|
class Deltatau:
|
|
def __init__(self,sim=False):
|
|
app=QApplication.instance()
|
|
cfg=app._cfg
|
|
host=cfg.value(AppCfg.DT_HOST)
|
|
# sim=False;host='localhost:10001:10002' # this only moves motors during acquisition
|
|
if sim:
|
|
self._comm=comm=None
|
|
self._gather=gather=None
|
|
else:
|
|
hpp=host.split(':')
|
|
param={'host':hpp[0]}
|
|
if len(hpp)>1:
|
|
param['port']=int(hpp[1])
|
|
if len(hpp)>2:
|
|
param['fast_gather_port']=int(hpp[2])
|
|
_log.info(' -> ssh-tunneling PPComm({host}:{port} {host}:{fast_gather_port})'.format(**param))
|
|
try:
|
|
self._comm=comm=PPComm(**param,timeout=2.0)
|
|
self._gather=gather=Gather(comm)
|
|
except (socket.timeout,socket.gaierror) as e:
|
|
_log.critical(f'can not connect to deltatau:"{host}" -> {e}')
|
|
self._shapepath=sp=shapepath.ShapePath(comm, gather, verbose=0xff, sync_mode=1, sync_flag=3)
|
|
|
|
class Jungfrau:
|
|
def __init__(self,sim=False):
|
|
#python /sf/jungfrau/applications/daq_client/daq_client.py -h
|
|
#python /sf/jungfrau/applications/daq_client/daq_client.py -p p19739 -t no_beam_test
|
|
# -c/sf/cristallina/config/channel_lists/channel_list_bs-e/sf/cristallina/config/channel_lists/channel_list_ca
|
|
# -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
|
|
if sim:
|
|
self._sim=True
|
|
return
|
|
try:
|
|
self._pv_pulse_id=epics.PV('SAR-EXPMX-EVR0:RX-PULSEID')
|
|
self._pv_pulse_id.connect()
|
|
except NameError as e:
|
|
_log.critical(f'Jungfrau not connected: {e}')
|
|
|
|
def config(self,**kwargs):
|
|
if getattr(self,'_sim',False):
|
|
_log.info(f'simulated')
|
|
return
|
|
app=QApplication.instance() #temproary fix, couldnt access these in function, maybe the bt above needs to be self.detectors ... etc
|
|
cfg=app._cfg
|
|
det = cfg.value(AppCfg.DAQ_DET)
|
|
print("det", repr(det))
|
|
detectors = [det] if det.get("name") else None
|
|
bs_channels = cfg.value(AppCfg.DAQ_BS_CH)
|
|
pv_channels = cfg.value(AppCfg.DAQ_PV_CH)
|
|
loc=cfg.value(AppCfg.DAQ_LOC)
|
|
dt_misc = cfg.value(AppCfg.DT_MISC)
|
|
code_gen=kwargs.get('code_gen',0)
|
|
sync_mode=dt_misc['sync_mode']
|
|
sync_flag=dt_misc['sync_flag']
|
|
if loc['jungfraujoch']:
|
|
try:
|
|
self.jfj = JFJ("http://sf-daq-2:5232")
|
|
self.detectors=None
|
|
except:
|
|
self.jfj = None
|
|
else:
|
|
self.jfj = None
|
|
if sync_flag==0:
|
|
grid_cnt=kwargs['grid']['count']
|
|
repetitions=grid_cnt[0] #'x' or number of columns
|
|
cta_multiplier=grid_cnt[1] #'y' or number of appertures in a column/number of rows
|
|
cta=CTASequencer("SAR-CCTA-ESC")
|
|
if code_gen==3:
|
|
wait_pulses=kwargs['twait']//kwargs['tmove']
|
|
#xray_seq=[0,]*wait_pulses+[1] # multiplier is proportional to wait_time i.e. 10 ms = 1, 20 ms =2, 30 ms =3.
|
|
xray_seq=[1,]+[0,]*wait_pulses
|
|
cta.seq[200]=xray_seq*cta_multiplier # x-ray_shutter
|
|
laser_seq=[1,]*wait_pulses+[1]
|
|
cta.seq[215]=laser_seq*cta_multiplier # laser_shutter
|
|
droplet_sequence=[0, 1, 0, 0] # sub 8 ms delay = [0, 0, 1, 0]
|
|
cta.seq[216]=droplet_sequence*(cta_multiplier//2)
|
|
cta.seq[214]=[1,]+[0,]*(len(laser_seq*cta_multiplier)-1)
|
|
else:
|
|
print('not code gen 3')
|
|
#cta_multiplier-=14
|
|
#cta.seq[200]=[0,0,0,0,0,0,0]+[1,]*cta_multiplier + [0,0,0,0,0,0,0] # for +7 row chip x-ray
|
|
#cta.seq[215]=[0,0,0,0,0,0,0]+[1,]*cta_multiplier + [0,0,0,0,0,0,0] # for +7 row chip laser
|
|
#cta.seq[214]=[1,0,0,0,0,0,0]+[0,]*cta_multiplier + [0,0,0,0,0,0,0] # for +7 row chip start
|
|
|
|
# no extra rows
|
|
cta.seq[214]=[1,]+[0,]*(cta_multiplier-1)
|
|
cta.seq[200]=[1,]*cta_multiplier # x-ray_shutter
|
|
#cta.seq[215]=[1,]*cta_multiplier # laser_shutter
|
|
#cta.seq[216]=[1,]*cta_multiplier # droplet_ejector all
|
|
cta.seq[216]=[1,0,]*(cta_multiplier//2) # droplet_ejector 1:1
|
|
#cta.seq[216]=[1,0,0,]*(cta_multiplier//3) # droplet_ejector 1:2
|
|
#cta.seq[216]=[1,0,0,0,0,0,]*(cta_multiplier//6) # droplet_ejector 1:5
|
|
#cta.seq[216]=[1,0,0,0,0,0,0,0,0,]*(cta_multiplier//9) # droplet_ejector 1:8
|
|
#cta.seq[216]=[1,0,0,0,0,0,0,0,0,0,0,0,]*(cta_multiplier//12) # droplet_ejector 1:11
|
|
|
|
# skip 6 rows add 6 on end -- first 2 and 1 216
|
|
#cta.seq[214]=[1,0,0,0,0,0,]+[0,]*(cta_multiplier-12)+[0,0,0,0,0,0,]
|
|
#cta.seq[200]=[0,0,0,0,0,0,]+[1,]*(cta_multiplier-12)+[0,0,0,0,0,0,] # x-ray_shutter
|
|
#cta.seq[216]=[0,0,0,0,0,0,]+[1,]*(cta_multiplier-12)+[0,0,0,0,0,0,] # droplet_ejector all
|
|
#cta.seq[216]=[0,0,0,0,0,0,]+[1,0,]*((cta_multiplier-12)//2)+[0,0,0,0,0,0,] # droplet_ejector 1:1
|
|
#cta.seq[216]=[0,0,0,0,0,0,]+[1,0,0,]*((cta_multiplier-12)//3)+[0,0,0,0,0,0] # droplet_ejector 1:2
|
|
#cta.seq[216]=[0,0,0,0,0,0,]+[1,0,0,0]*((cta_multiplier-12)//4)+[0,0,0,0,0,0] # droplet_ejector 1:3
|
|
#cta.seq[216]=[0,0,0,0,0,0,]+[1,0,0,0,0,0,]*((cta_multiplier-12)//6)+[0,0,0,0,0,0]# droplet_ejector 1:5
|
|
#cta.seq[216]=[0,0,0,0,0,0,]+[1,0,0,0,0,0,0,0,0,0,0,0,]*((cta_multiplier-12)//12)+[0,0,0,0,0,0] # droplet_ejector 1:11
|
|
cta.cfg.repetitions=repetitions # self._cta.cfg.repetitions = n_pulses_run/cta_multiplier
|
|
cta.seq.upload()
|
|
self._daq=CTAAcquisition(cta, 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)
|
|
else:
|
|
self._daq=SFAcquisition(
|
|
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)
|
|
|
|
def acquire(self, n_pulses, wait=False):
|
|
if getattr(self,'_sim',False):
|
|
_log.info(f'simulated')
|
|
return
|
|
try:
|
|
daq=self._daq
|
|
except AttributeError:
|
|
_log.info(f'simulated')
|
|
return
|
|
app=QApplication.instance()
|
|
cfg=app._cfg
|
|
run=cfg.value(AppCfg.DAQ_RUN)
|
|
try:
|
|
self._pulse_id_start=int(self._pv_pulse_id.value)
|
|
except TypeError as e:
|
|
_log.warning(f'failed to get _pulse_id_start: {e}')
|
|
n_pulses_run = n_pulses + run['padding']
|
|
n_pulses_run*=2 # comment me out please when not using 10 ms wait (for stop and go)
|
|
print('number of triggers ', n_pulses_run, ' is greater than the number of appertures', n_pulses)
|
|
block_size = run['block_size']
|
|
if self.jfj:
|
|
self.jfj.acquire(beam_x_pxl = 1613, beam_y_pxl = 1666, detector_distance_mm = 151, photon_energy_keV = 12, sample_name = run['cell_name'], file_prefix = run['prefix'], ntrigger = n_pulses_run)
|
|
if type(self._daq) is CTAAcquisition:
|
|
self._daq.acquire(run['prefix'], n_pulses=max(n_pulses_run, block_size), n_block_size=block_size, wait=False, cell_name=run['cell_name'])
|
|
else:
|
|
self._daq.acquire(run['prefix'], n_pulses=max(n_pulses_run, block_size), n_repeat=ceil(n_pulses_run/block_size), wait=False, cell_name=run['cell_name'])
|
|
cfg.setValue(AppCfg.DAQ_RUN,run)
|
|
|
|
def gather_upload(self):
|
|
if getattr(self,'_sim',False):
|
|
_log.info(f'simulated')
|
|
return
|
|
try:
|
|
daq=self._daq
|
|
except AttributeError:
|
|
_log.info(f'simulated')
|
|
return
|
|
try:
|
|
self._pulse_id_end=int(self._pv_pulse_id.value)
|
|
except TypeError as e:
|
|
_log.warning(f'failed to get _pulse_id_start: {e}')
|
|
else:
|
|
_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()
|
|
|