0
0
forked from SwissFEL/c365
Files
c365/panel_psss.py
Claudio Cirelli 57c5012e45 change permissions
2026-02-20 15:16:38 +01:00

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)