forked from SwissFEL/c365
378 lines
15 KiB
Python
Executable File
378 lines
15 KiB
Python
Executable File
from collections import deque
|
|
import random, os
|
|
import wx
|
|
import numpy as np
|
|
import epics
|
|
|
|
from datetime import datetime
|
|
from scipy.stats.stats import pearsonr
|
|
|
|
#from epics.wx import MotorPanel
|
|
|
|
from slic.gui.widgets import LabeledMathEntry
|
|
from slic.gui.widgets import make_filled_hbox, make_filled_vbox, EXPANDING
|
|
from slic.gui.widgets.plotting import PlotPanel
|
|
|
|
from bstrd import BS, bsstream
|
|
|
|
|
|
# config
|
|
nshots = 50
|
|
qlength = 100
|
|
qlength2 =500
|
|
histlength = 1
|
|
qchecklen = 10
|
|
|
|
offset = 0 #in eV
|
|
Int_threshold = 100
|
|
DeltaE2move = 3
|
|
|
|
# channels
|
|
ENERGYpv = epics.PV('SARFE10-PSSS059:ENERGY')
|
|
CRYSTALpv = epics.PV('SARFE10-PSSS059:CRYSTAL_SP')
|
|
GRATINGpv = epics.PV('SARFE10-PSSS055:GRATING_SP')
|
|
SPECXpv = epics.PV('SARFE10-PSSS059:SPECTRUM_X')
|
|
SPECYpv = epics.PV('SARFE10-PSSS059:SPECTRUM_Y')
|
|
DCMpv = epics.PV('SAROP11-ARAMIS:ENERGY')
|
|
FELINTpv = epics.PV('SARFE10-PBPG050:PHOTON-ENERGY-PER-PULSE-AVG')
|
|
|
|
camArmRotpv = epics.PV('SARFE10-PSSS059:MOTOR_ROT_X4')
|
|
cristBendRotpv = epics.PV('SARFE10-PSSS059:MOTOR_ROT_X3')
|
|
cristBendRotpv_move = epics.PV('SARFE10-PSSS059:MOTOR_ROT_X3.MOVN')
|
|
camPosXpv = epics.PV('SARFE10-PSSS059:MOTOR_X5')
|
|
|
|
chname_pbpsint = "SAROP11-PBPS110:INTENSITY"
|
|
#chname_pbpsint = "SAROP21-PBPS103:INTENSITY"
|
|
#chname_pbpsint = "SAROP31-PBPS113:INTENSITY"
|
|
|
|
chname_psss_y = "SARFE10-PSSS059:SPECTRUM_Y"
|
|
chname_psss_x = "SARFE10-PSSS059:SPECTRUM_X"
|
|
chname_psss_com = "SARFE10-PSSS059:SPECT-COM"
|
|
#chname_psss_fwhm = "SARFE10-PSSS059:FIT-FWHM"
|
|
chname_psss_fwhm = "SARFE10-PSSS059:AVG-FIT-FWHM"
|
|
|
|
chname_events = "SAR-CVME-TIFALL4:EvtSet"
|
|
|
|
# create channels
|
|
ch_int = BS(chname_pbpsint)
|
|
ch_psssX = BS(chname_psss_x)
|
|
ch_psssY = BS(chname_psss_y)
|
|
ch_psssC = BS(chname_psss_com)
|
|
ch_psssW = BS(chname_psss_fwhm)
|
|
ch_events = BS(chname_events)
|
|
|
|
#iso_format = "%Y-%m-%d %H:%M:%S"
|
|
iso_format = "%H:%M:%S"
|
|
|
|
|
|
class MainPanel(wx.Panel):
|
|
|
|
def __init__(self, parent):
|
|
super().__init__(parent)
|
|
|
|
self.evts = np.empty((nshots,256))
|
|
self.iZero = np.empty(nshots)
|
|
self.psssX = np.empty((nshots,2560))
|
|
self.psssY = np.empty((nshots,2560))
|
|
self.psssC = np.empty(nshots)
|
|
self.psssW = np.empty(nshots)
|
|
|
|
self.energyAxis = np.empty(2560)
|
|
self.offset = 0
|
|
|
|
self.psssYs = deque(maxlen=qlength)
|
|
self.psssCs = deque(maxlen=qlength2)
|
|
self.psssCstds = deque(maxlen=qlength2)
|
|
self.psssWs = deque(maxlen=qlength)
|
|
self.checks = deque(maxlen=qchecklen)
|
|
|
|
self.iZeros = deque(maxlen=histlength)
|
|
self.psssIs = deque(maxlen=histlength)
|
|
|
|
self.plot_spectra = plot_spectra = PlotPanel(self, figsize=(6,3))
|
|
self.plot_center = plot_center = PlotPanel(self, figsize=(3,3))
|
|
self.plot_int = plot_int = PlotPanel(self, figsize=(3,3))
|
|
self.plot_width = plot_width = PlotPanel(self, figsize=(3,3))
|
|
|
|
plots1 = (plot_spectra, )
|
|
plots2 = (plot_center, )
|
|
plots3 = (plot_int, plot_width)
|
|
|
|
hb_plot1 = make_filled_hbox(plots1)
|
|
hb_plot2 = make_filled_hbox(plots2)
|
|
hb_plot3 = make_filled_hbox(plots3)
|
|
|
|
btn_clearQ = wx.Button(self, label="Clear plots")
|
|
btns = (btn_clearQ,)
|
|
#hb_btns = make_filled_hbox(btns)
|
|
|
|
self.chkbx_follow = chkbx_follow = wx.CheckBox(self, label="follow")
|
|
chkbxs = (btn_clearQ, chkbx_follow)
|
|
hb_chkbx = make_filled_hbox(chkbxs)
|
|
|
|
widgets = (hb_plot1, hb_plot2, hb_plot3, hb_chkbx)
|
|
box = make_filled_vbox(widgets, border=1)
|
|
self.SetSizerAndFit(box)
|
|
|
|
btn_clearQ.Bind(wx.EVT_BUTTON, self.on_click_clearQ)
|
|
|
|
self.timer = wx.Timer(self)
|
|
self.Bind(wx.EVT_TIMER, self.on_update, self.timer)
|
|
self.timer.Start(100)
|
|
|
|
|
|
def on_update(self, _event):
|
|
|
|
self.time = datetime.now().strftime(iso_format)
|
|
|
|
self.evts = np.empty((nshots,256))
|
|
self.iZero = np.empty(nshots)
|
|
self.psssX = np.empty((nshots,2560)) #2560 for narrow bandwidth camera
|
|
self.psssY = np.empty((nshots,2560))
|
|
self.psssC = np.empty(nshots)
|
|
self.psssW = np.empty(nshots)
|
|
|
|
for i in range(nshots):
|
|
tempa = ch_events.get()
|
|
self.evts[i] = tempa
|
|
tempb = ch_int.get()
|
|
self.iZero[i] = tempb
|
|
tempc = ch_psssX.get()
|
|
self.psssX[i] = tempc
|
|
tempd = ch_psssY.get()
|
|
self.psssY[i] = tempd
|
|
tempe = ch_psssC.get()
|
|
self.psssC[i] = tempe
|
|
tempf = ch_psssW.get()
|
|
self.psssW[i] = tempf
|
|
next(bsstream)
|
|
wx.GetApp().Yield()
|
|
|
|
self.current_energy = ENERGYpv.get()
|
|
self.current_crystal = CRYSTALpv.get()
|
|
self.current_grating = GRATINGpv.get()
|
|
self.current_dcm = DCMpv.get()
|
|
self.current_Int = FELINTpv.get()
|
|
|
|
fnXtlLst=(None,"Si111R155","Si220R75","Si220R145","Si220R200","Si333R155")
|
|
base=os.path.dirname(__file__)
|
|
fn=os.path.join(base,'lut'+fnXtlLst[CRYSTALpv.get()]+'.txt')
|
|
lut= np.genfromtxt(fn, delimiter='\t',names=True)
|
|
#print (fn)
|
|
|
|
camPosX='CamPosX'
|
|
if self.current_grating in(1,2):camPosX+='_100nm'
|
|
elif self.current_grating==3:camPosX+='_150nm'
|
|
elif self.current_grating==4:camPosX+='_200nm'
|
|
|
|
camArmRot =np.interp(self.current_energy,lut['Energy'],lut['CamArmRot'])
|
|
cristBendRot=np.interp(self.current_energy,lut['Energy'],lut['CristBendRot'])
|
|
camPosX =np.interp(self.current_energy,lut['Energy'],lut[camPosX])
|
|
evPerPix =np.interp(self.current_energy,lut['Energy'],lut['EvPerPix'])
|
|
|
|
self.psssYs = np.mean(self.psssY, axis=0)
|
|
self.psssXs = np.mean(self.psssX, axis=0)
|
|
|
|
#print (max(self.psssYs), self.current_Int, Int_threshold)
|
|
|
|
if (self.current_Int > Int_threshold):# & (max(self.psssYs)>1000):
|
|
|
|
self.iZeros.append(self.iZero)
|
|
self.psssIs.append(np.sum(self.psssY, axis=1))
|
|
self.psssCs.append(np.mean(self.psssC))
|
|
self.psssCstds.append(np.std(self.psssC))
|
|
self.psssWs.append(np.mean(self.psssW))
|
|
|
|
#print (current_energy, current_crystal, current_grating)
|
|
|
|
self.offset = np.mean(self.psssC) - self.current_dcm
|
|
|
|
self.howfar = abs(np.mean(self.psssC) - self.current_energy)
|
|
self.check = abs(np.mean(self.psssC) - self.current_energy) > DeltaE2move
|
|
self.checks.append(self.check)
|
|
|
|
print (self.time, np.mean(self.psssC), self.current_energy, self.howfar)
|
|
#print (np.sum(self.checks))
|
|
moving = cristBendRotpv_move.get()
|
|
#print (moving)
|
|
|
|
n=2560
|
|
i=np.arange(n)-n/2
|
|
spctr_x = (self.current_energy)+i*evPerPix
|
|
#spctr_x = (np.mean(self.psssC))+i*evPerPix
|
|
SPECXpv.put(spctr_x)
|
|
self.energyAxis=SPECXpv.get()
|
|
|
|
if (self.chkbx_follow.IsChecked()):
|
|
if (np.sum(self.checks)==qchecklen) & (moving==0) & (self.current_Int > Int_threshold):
|
|
#if (abs((np.mean(self.psssC) - self.current_dcm))>DeltaE2move) & (self.current_Int > Int_threshold):
|
|
print ('-----------------------')
|
|
print ("Off by {} eV: move!".format(self.howfar))
|
|
|
|
energy2go = int(np.mean(self.psssC))
|
|
#print (int(energy2go))
|
|
|
|
camArmRot =np.interp(energy2go,lut['Energy'],lut['CamArmRot'])
|
|
cristBendRot=np.interp(energy2go,lut['Energy'],lut['CristBendRot'])
|
|
#camPosX =np.interp(energy2go,lut['Energy'],lut[camPosX])
|
|
#camPosX =np.interp(energy2go,lut['Energy'],lut['camPosX'])
|
|
evPerPix =np.interp(energy2go,lut['Energy'],lut['EvPerPix'])
|
|
|
|
ENERGYpv.put(energy2go)
|
|
camArmRotpv.put(camArmRot)
|
|
cristBendRotpv.put(cristBendRot)
|
|
camPosXpv.put(camPosX)
|
|
print (energy2go, camArmRot, cristBendRot, camPosX, evPerPix)
|
|
print ('-----------------------')
|
|
|
|
self.current_energy = ENERGYpv.get()
|
|
self.current_crystal = CRYSTALpv.get()
|
|
self.current_grating = GRATINGpv.get()
|
|
#print (self.current_energy, camArmRot, cristBendRot, camPosX, evPerPix)
|
|
|
|
else:
|
|
print("{}: FEL intensity = {:.1f} uJ, No signal".format(self.time, self.current_Int))
|
|
self.iZeros.append(np.nan)
|
|
self.psssIs.append(np.nan)
|
|
self.psssCs.append(np.nan)
|
|
self.psssCstds.append(np.nan)
|
|
self.psssWs.append(np.nan)
|
|
|
|
self.draw_plot()
|
|
|
|
|
|
|
|
def draw_plot(self):
|
|
|
|
self.plot_spectra.clear()
|
|
self.plot_center.clear()
|
|
self.plot_int.clear()
|
|
self.plot_width.clear()
|
|
|
|
self.plot_spectra.set_xlabel('Energy (eV)')
|
|
self.plot_spectra.set_ylabel('Intensity, a.u.')
|
|
self.plot_center.set_xlabel('time ago, a.u.')
|
|
self.plot_center.set_ylabel('Energy (eV)')
|
|
self.plot_int.set_xlabel('PSSS Int')
|
|
self.plot_int.set_ylabel('{}'.format(chname_pbpsint))
|
|
self.plot_width.set_xlabel('time ago, a.u.')
|
|
self.plot_width.set_ylabel('Energy (eV)')
|
|
|
|
if len(self.psssCs)>3:
|
|
self.plot_spectra.plot(self.energyAxis, self.psssY[random.randrange(0, len(self.psssY))], color='limegreen', linewidth=0.5)
|
|
self.plot_spectra.plot(self.energyAxis, self.psssY[random.randrange(0, len(self.psssY))], color='limegreen', linewidth=0.5)
|
|
self.plot_spectra.plot(self.energyAxis, self.psssY[random.randrange(0, len(self.psssY))], color='limegreen', linewidth=0.5)
|
|
#self.plot_spectra.plot(self.energyAxis, self.psssY[random.randrange(0, len(self.psssY))], color='limegreen', linewidth=0.5)
|
|
#self.plot_spectra.plot(self.energyAxis, self.psssY[random.randrange(0, len(self.psssY))], color='limegreen', linewidth=0.5)
|
|
|
|
if np.isnan(np.array(self.psssCs)).all() != True:
|
|
self.plot_spectra.axvline(x=self.psssCs[-1], color = 'black', linestyle = '--')
|
|
self.plot_spectra.axvline(x=self.psssCs[-2], color = 'dimgrey', linestyle = '--')
|
|
self.plot_spectra.axvline(x=self.psssCs[-3], color = 'grey', linestyle = '--')
|
|
self.plot_spectra.axvline(x=self.psssCs[-4], color = 'silver', linestyle = '--')
|
|
self.plot_spectra.axvline(x=self.psssCs[-5], color = 'lightgrey', linestyle = '--')
|
|
|
|
self.plot_spectra.set_title('Central energy: {:.2f} eV'.format(self.psssCs[-1]))
|
|
self.plot_center.set_title('Central energy')
|
|
self.plot_width.set_title('Width: {:.4f}%'.format(self.psssWs[-1]/self.psssCs[-1]*100))
|
|
|
|
try: #np.isnan(np.array(self.psssCs)).all() != True:
|
|
#self.plot_spectra.axvline(x=self.psssCs[-1], color = 'black', linestyle = '--')
|
|
#self.plot_spectra.axvline(x=self.psssCs[-2], color = 'dimgrey', linestyle = '--')
|
|
#self.plot_spectra.axvline(x=self.psssCs[-3], color = 'grey', linestyle = '--')
|
|
#self.plot_spectra.axvline(x=self.psssCs[-4], color = 'silver', linestyle = '--')
|
|
#self.plot_spectra.axvline(x=self.psssCs[-5], color = 'lightgrey', linestyle = '--')
|
|
self.plot_int.set_title('Correlation: {:.4f}'.format(pearsonr(np.roll(np.ravel(self.psssIs), 0), np.ravel(self.iZeros))[0]))
|
|
self.plot_center.set_ylim(self.current_energy-np.asarray(np.nanmean(self.psssWs)), self.current_energy+np.asarray(np.nanmean(self.psssWs)))
|
|
self.plot_spectra.axvline(x=(self.current_dcm+self.offset), color = 'red', linestyle = '--')
|
|
self.plot_center.fill_between(np.arange(0, len(self.psssCs)), np.asarray(self.psssCstds)+np.asarray(self.psssCs), -np.asarray(self.psssCstds)+np.asarray(self.psssCs), color='gold')
|
|
except:
|
|
self.plot_int.set_title('Correlation: NaN')
|
|
|
|
self.plot_center.grid()
|
|
|
|
self.plot_spectra.plot(self.energyAxis, self.psssYs, '-', color='green')
|
|
self.plot_center.plot(np.arange(0, len(self.psssCs)), self.psssCs, color='orangered' )
|
|
self.plot_int.plot(np.ravel(self.psssIs), np.ravel(self.iZeros), '.', color='purple')
|
|
self.plot_width.plot(np.arange(0, len(self.psssWs)), self.psssWs, color='royalblue', linewidth=0.5)
|
|
|
|
self.plot_spectra.draw()
|
|
self.plot_center.draw()
|
|
self.plot_int.draw()
|
|
self.plot_width.draw()
|
|
|
|
|
|
def on_click_clearQ(self, _event):
|
|
|
|
self.plot_spectra.clear()
|
|
self.plot_center.clear()
|
|
self.plot_int.clear()
|
|
self.plot_width.clear()
|
|
|
|
|
|
def set_energy_motor(self,energy2motor,scan=False, rotWait=False):
|
|
|
|
if CRYSTALpv==0: return
|
|
|
|
#load lut
|
|
fnXtlLst=(None,"Si111R155","Si220R75","Si220R145","Si220R200","Si333R155")
|
|
#print(__file__)
|
|
base=os.path.dirname(__file__)
|
|
fn=os.path.join(base,'lut'+fnXtlLst[CRYSTALpv]+'.txt')
|
|
lut= np.genfromtxt(fn, delimiter='\t',names=True)
|
|
#lut
|
|
#lut.dtype
|
|
#lut[1]['Energy']
|
|
#lut['Energy']
|
|
#lut=np.genfromtxt(fn, delimiter='\t',skip_header=1)
|
|
if energy2motor:
|
|
energy = ENERGYpv.get()# self.getPv('PSSS059:ENERGY').getw()
|
|
#energy =6000
|
|
gratingType=self.getPv('PSSS055:GRATING_SP').getw()
|
|
#gratingType=3
|
|
camPosX='CamPosX'
|
|
if gratingType in(1,2):camPosX+='_100nm'
|
|
elif gratingType==3:camPosX+='_150nm'
|
|
elif gratingType==4:camPosX+='_200nm'
|
|
|
|
camArmRot =np.interp(energy,lut['Energy'],lut['CamArmRot'])
|
|
cristBendRot=np.interp(energy,lut['Energy'],lut['CristBendRot'])
|
|
camPosX =np.interp(energy,lut['Energy'],lut[camPosX])
|
|
evPerPix =np.interp(energy,lut['Energy'],lut['EvPerPix'])
|
|
else:
|
|
camArmRot=self.getPv('PSSS059:MOTOR_ROT_X4').getw()
|
|
idx=~np.isnan(lut['CamArmRot'])
|
|
lutCamArmRot=lut['CamArmRot'][idx]
|
|
energy =np.interp(camArmRot,lutCamArmRot[::-1],lut['Energy'][idx][::-1])
|
|
evPerPix =np.interp(camArmRot,lutCamArmRot[::-1],lut['EvPerPix'][idx][::-1])
|
|
|
|
#camera: 2560 x 2160
|
|
n=2560
|
|
i=np.arange(n)-n/2
|
|
spctr_x=energy+i*evPerPix
|
|
pv=self.getPv('PSSS059:SPECTRUM_X')
|
|
pv.putw(spctr_x)
|
|
|
|
pv=self.getPv('PSSS059:SPECTRUM_Y')
|
|
mu=2560./2
|
|
sigma=100.
|
|
x=np.arange(2560.)
|
|
spctr_y= 1000.*np.exp(-( (x-mu)**2 / ( 2.0 * sigma**2 ) ) )
|
|
pv.putw(spctr_y)
|
|
|
|
if energy2motor:
|
|
print('energy2motor: camArmRot: %g cristBendRot: %g camPosX:%g evPerPix:%g'%(camArmRot,cristBendRot,camPosX,evPerPix))
|
|
pv=self.getPv('PSSS059:MOTOR_ROT_X4')
|
|
pv.putw(camArmRot)
|
|
pv=self.getPv('PSSS059:MOTOR_ROT_X3')
|
|
pv.putw(cristBendRot)
|
|
if rotWait == True:
|
|
self.waitMotionDone('PSSS059:MOTOR_ROT_X3')
|
|
if scan == False: # if True the camera X position will not be changed
|
|
pv=self.getPv('PSSS059:MOTOR_X5')
|
|
pv.putw(camPosX)
|
|
else:
|
|
print('motor2energy: energy: %g evPerPix:%g'%(energy,evPerPix))
|
|
pv=self.getPv('PSSS059:ENERGY')
|
|
pv.putw(energy)
|