#!/usr/bin/env python2 # -*- coding: utf-8 -*- """ Gun Phase scan Created in quarantena 2020 @author: mauro """ #import os import sys import numpy as np import PyTango import h5py import time from PyQt4.QtCore import * from PyQt4.QtGui import * from scipy.interpolate import interp1d from scipy.optimize import minimize_scalar from threading import Thread #from matplotlib import pyplot as plt from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas #from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar from matplotlib.figure import Figure # variabili globali # phase_offset = 0 treadOut = [] # un dictionary for i device: t_dev = {} try: t_dev['pil_sh'] = PyTango.DeviceProxy('srv-tango-srf-01:20000/usa/mps/shutter') # ->Close, Open State t_dev['inj_current'] = PyTango.DeviceProxy('srv-tango-srf-01:20000/inj/diagnostics/cm_inj.01') t_dev['charge_fb'] = PyTango.DeviceProxy('srv-tango-srf-01:20000/f/feedback/charge_fb.01') t_dev['timing'] = PyTango.DeviceProxy('srv-tango-srf-01:20000/f/timing/bunchnumber_f') #,'BunchNumberFrequency' t_dev['llrf_k1'] = PyTango.DeviceProxy('srv-tango-srf-01:20000/kg01/mod/llrf_kg01.01') #'cav_phase_set' t_dev['mod_k1'] = PyTango.DeviceProxy('srv-tango-srf-01:20000/kg01/mod/rfamp') t_dev['llrf_ks'] = PyTango.DeviceProxy('srv-tango-srf-01:20000/kgsp/mod/llrf_kgsp.01') t_dev['pil_en'] = PyTango.DeviceProxy('srv-tango-srf-01:20000/pil/energy_meter/eml_pil.01') except PyTango.DevFailed: print('error defining device, DeviceProxys') ##################### class PhaScan(): def __init__(self, inputs): """dati scan""" self.inputs = inputs # [startphase, stopphase, stepphase, n_shot] self.phases = np.linspace(inputs[0], inputs[1], num=(int((inputs[1]-inputs[0])/inputs[2])+1), endpoint=True) self.currents = np.zeros(len(self.phases)) self.curr_errors = np.zeros(len(self.phases)) def getscan(self): rnmCheck = False # % wave dei valori di fase: phase_wave = [] for i in range(int(self.inputs[3])): phase_wave.extend(self.phases) phase_wave.sort() phaseWaveform = np.fmod(phase_wave, 360) # % set number of waveform cycles (WaveLoopMode must be set to 0) a = 1; t_dev['llrf_k1'].write_attribute('PhaseWaveformNumCycles', 1) t_dev['llrf_k1'].write_attribute('PhaseWaveformAbsMode', True) # False # % load waveform t_dev['llrf_k1'].write_attribute('PhaseWaveform', phaseWaveform) # % set current waveform as absolute value, a=1; t_dev['llrf_k1'].write_attribute('PhaseWaveformAbsMode', True) # False if t_dev['llrf_k1'].read_attribute('RnmMode').value: rnmCheck = True t_dev['llrf_k1'].write_attribute('RnmMode', False) # False # % read current bunch number b_stemp = t_dev['timing'].read_attribute('BunchNumber') bunchstart = b_stemp.value + 20 #print(bunchstart) # % set bunch number start t_dev['llrf_k1'].write_attribute('PhaseWaveformBunchNumberStart', bunchstart) t_dev['llrf_k1'].command_inout('PhaseWaveformStart') # aspetto che sia finita la wave frequenza pari try: freq = t_dev['timing'].read_attribute('BunchNumberFrequency') # print(freq.value) frequenza = freq.value except PyTango.DevFailed: print('error reading Frequency') frequenza = 10 time.sleep(((len(phase_wave)) / frequenza) + 1) indice = [1, bunchstart+1, (bunchstart +1+ len(phase_wave))] bunch_shots = t_dev['inj_current'].command_inout('GetCharge', indice) for i in range(len(self.phases)): self.currents[i] = np.mean(bunch_shots[int(self.inputs[3])*i : int(self.inputs[3])*(i+1)]) self.curr_errors[i] = np.std(bunch_shots[int(self.inputs[3])*i : int(self.inputs[3])*(i+1)]) t_dev['llrf_k1'].command_inout('PhaseWaveformAbort') if rnmCheck: t_dev['llrf_k1'].write_attribute('RnmMode', True) output = [self.phases, self.currents, self.curr_errors] return output ##################### class Lancio(Thread): def __init__(self, nome, inputs): Thread.__init__(self) self.nome = nome self.input = inputs def __del__(self): self.exiting = False #self.wait() def run(self): ph_scan = PhaScan(self.input) global treadOut treadOut = ph_scan.getscan() ############################################################################### class MainWindow(QDialog): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setWindowTitle("Gun phase scan") self.dati_scan = [] self.phase_offset = 0 # input ############################################################### larghezzal = 90 self.gruppo_input = QGroupBox('Inputs') #self.gruppo_input.setStyleSheet("border: 1px solid #E77200") self.gruppo_input.setStyleSheet("color : blue") self.label1 = QLabel("Start phase") self.label1.setMaximumWidth(larghezzal) self.startphase = QDoubleSpinBox() self.startphase.setSingleStep(5) self.startphase.setMinimum(0.0) self.startphase.setMaximum(500.0) self.startphase.setValue(250) self.label2 = QLabel("Stop phase") self.label2.setMaximumWidth(larghezzal) self.stopphase = QDoubleSpinBox() self.stopphase.setSingleStep(5) self.stopphase.setMinimum(0.0) self.stopphase.setMaximum(500.0) self.stopphase.setValue(400) self.label3 = QLabel("Step") self.label3.setMaximumWidth(larghezzal) self.stepphase = QDoubleSpinBox() self.stepphase.setSingleStep(1) self.stepphase.setMinimum(1.0) self.stepphase.setMaximum(15.0) self.stepphase.setValue(3) self.label4 = QLabel("n. shots") self.label4.setMaximumWidth(larghezzal) self.n_shot = QDoubleSpinBox() self.n_shot.setSingleStep(1) self.n_shot.setMinimum(2.0) self.n_shot.setMaximum(20.0) self.n_shot.setValue(5) self.combo = QComboBox() self.combo.addItem("No knee - 80 MV/m") self.combo.addItem("Low knee - 80 MV/m") self.combo.addItem("High knee - 80 MV/m") self.combo.addItem("No knee - 100 MV/m") self.combo.addItem("Low knee - 100 MV/m") self.combo.addItem("High knee - 100 MV/m") self.combo.addItem("Low knee - 5 ps") self.combo.addItem("High knee - 5 ps") self.combo.setCurrentIndex(7) # definisco un default layoutinput = QFormLayout() layoutinput.addRow(self.label1, self.startphase) layoutinput.addRow(self.label2, self.stopphase) layoutinput.addRow(self.label3, self.stepphase) layoutinput.addRow(self.label4, self.n_shot) layoutinput.addRow(self.combo) self.gruppo_input.setLayout(layoutinput) # actions ######################################################################################################## self.gruppo_action = QGroupBox('Actions') #self.gruppo_action.setStyleSheet("border: 1px solid #009DC4") self.gruppo_action.setStyleSheet("color : navy") self.tasto_scan = QPushButton('Start SCAN') self.tasto_scan.setCheckable(True) self.tasto_scan.setStyleSheet("background-color : aqua") # self.tasto_scan.clicked.connect(self.btnstate) self.tasto_scan.clicked.connect(self.phasescanstart) self.tasto_save = QPushButton('SAVE Data') self.tasto_save.clicked.connect(self.savedata) self.tasto_save.setEnabled(False) self.tasto_fit = QPushButton('FIT Data') self.tasto_fit.clicked.connect(self.fitdataset) self.tasto_fit.setEnabled(False) self.delta_phase = QDoubleSpinBox() self.delta_phase.setSingleStep(0.2) self.delta_phase.setMinimum(-50.0) self.delta_phase.setMaximum(-10.0) self.delta_phase.setValue(-30) self.tasto_setph = QPushButton('SET Phase') self.tasto_setph.clicked.connect(self.phaseK1set) self.tasto_setph.setEnabled(False) layoutaction = QVBoxLayout() layoutaction.addWidget(self.tasto_scan) layoutaction.addWidget(self.tasto_fit) layoutaction.addWidget(self.delta_phase) layoutaction.addWidget(self.tasto_setph) layoutaction.addWidget(self.tasto_save) self.gruppo_action.setLayout(layoutaction) # a figure instance to plot on self.figure1 = Figure(figsize=(3.8, 3.8)) # this is the Canvas Widget that displays the `figure` # it takes the `figure` instance as a parameter to __init__ self.canvas1 = FigureCanvas(self.figure1) self.ax1 = self.figure1.add_subplot(211) self.ax2 = self.figure1.add_subplot(212) ### layout generale #################################### loglobale = QGridLayout() loglobale.addWidget(self.gruppo_input, 0, 0, 1, 1) loglobale.addWidget(self.gruppo_action, 1, 0, 1, 1) loglobale.addWidget(self.canvas1, 0, 1, 2, 1) self.setLayout(loglobale) self.show() # definiamo i metodi: ############fuinzione di servizio per il display di messaggio ########### def showdialog_e(self, s_testo): msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setText(s_testo) # msg.setInformativeText("This is additional information") msg.setWindowTitle("Error Message") # msg.setDetailedText("The details are as follows:") msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) # msg.buttonClicked.connect(msgbtn) msg.exec_() # print "value of pressed message box button:", retval def btnstate(self): if self.tasto_scan.isChecked(): self.tasto_scan.setText('Scan done') else: self.tasto_scan.setText('SCAN done') ############fuinzioni che fanno qualcosa ########### def phasescanstart(self): # inserisco il controllo sullo stato del feedback di carica: DA VERIFICARE status_fb_q = t_dev['charge_fb'].read_attribute('State') if (status_fb_q.value) == 0: l1 = "Please, STOP the Charge feedback before scanning!" self.showdialog_e(l1) self.tasto_scan.toggle() return -1 #status_pilsh = t_dev['pil_sh'].read_attribute('State') if 'CLOSE' in str(status_pilsh): status_pilsh = t_dev['pil_sh'].command_inout('State') if 'CLOSE' in str(status_pilsh): l2 = "PIL shutter is closed, OPEN before scanning!" self.showdialog_e(l2) self.tasto_scan.toggle() return -1 # leggo la fase iniziale: try: phase_start = t_dev['llrf_k1'].read_attribute('cav_phase_set') phase_in = phase_start.value except PyTango.DevFailed: print('error reading phase in, DeviceProxys') pass w_title = "Gun phase scan " + time.strftime("%H:%M") self.setWindowTitle(w_title) self.tasto_scan.setText('Scan running ...') self.show() # costruisco l'imput dello scan inputs = [self.startphase.value(), self.stopphase.value(), self.stepphase.value(), self.n_shot.value()] thread_scan = Lancio("scan1", inputs) thread_scan.start() # Return whether the thread is alive. # while thread_scan.is_alive(): while thread_scan.isAlive(): bunch_shot = t_dev['inj_current'].command_inout('GetCharge', [0,200]) self.ax1.clear() self.ax1.plot(bunch_shot, 'b') # refresh canvas self.canvas1.repaint() self.canvas1.draw() time.sleep(0.3) self.dati_scan = treadOut # ripristino la fase t_dev['llrf_k1'].write_attribute('cav_phase_set', phase_in) # plot data self.ax1.clear() self.ax2.clear() # self.ax1.plot(dati_scan(1), dati_scan(2), '*-b') self.ax1.errorbar(self.dati_scan[0], self.dati_scan[1], yerr=self.dati_scan[2], xerr=None, fmt='.-g') # refresh canvas self.canvas1.draw() # abilito i tasti successivi self.tasto_save.setEnabled(True) self.tasto_fit.setEnabled(True) self.tasto_scan.setText('Re Start SCAN') self.tasto_scan.toggle() return 0 def fitdataset(self): x_scan = self.dati_scan[0] y_scan = self.dati_scan[1] y_scan_norm = np.divide(y_scan - min(y_scan),(max(y_scan) - min(y_scan))) #da provare # y_scan_norm = np.divide(y_scan, max(y_scan)) # cerco il massimo range = x_scan[np.argmax(y_scan)] + 90. # dati delle simulazioni estratti dal file scans.... f1 = h5py.File('PhaseScans.hdf5', 'r') dset = f1['phase_scans'] x_sim = dset[0,:] y_sim = dset[(self.combo.currentIndex()+1),:] #creo la funzione di interpolazione necesaria poco dopo: f_int = interp1d(x_sim, y_sim, kind='cubic', bounds_error=False, fill_value=0) # definisco la funzione che parametrizza la distanza in fase tra le curve: def diffDataConOffset(shift): punti = y_scan_norm * f_int(x_scan - shift) return 1./np.sum(punti) # a funzione che minimizza: res = minimize_scalar(diffDataConOffset, bounds=(range -30, range + 30), method='bounded') self.phase_offset = res.x offest_s = "%.1f" % self.phase_offset # trasformo il numero in stringa per dopo # parte grafica di output self.ax2.clear() self.ax2.plot((x_scan - res.x), y_scan_norm, '.g', x_sim, y_sim, 'r') self.ax2.set_xlabel('Offset = ' + offest_s + ' deg') # refresh canvas self.canvas1.draw() f1.close() self.tasto_setph.setEnabled(True) def phaseK1set(self): phase_value = self.delta_phase.value() + self.phase_offset print(phase_value) # mi assicuro che il valore sia buono if phase_value > 360: phase_value = phase_value - 360 if phase_value < 0: phase_value = phase_value + 360 t_dev['llrf_k1'].write_attribute('cav_phase_set', phase_value) # definisco la cresta di K1 time.sleep(0.5) t_dev['mod_k1'].command_inout('ResetKlystronPhase') def savedata(self, dati): # recupero la PIL energy: pil_energy = t_dev['pil_en'].read_attribute('Corrected_energy') pil_energy_v = pil_energy.value # % compongo la stringa per il salvataggio: pathf = '/home/fermi/data/ShottkyScan/runXX/' # filename = 'ShScan_'+ time.strftime("%Y%m%d_%H%M%S") filename = 'ShScan_'+ time.strftime("%Y%m%d_%H%M") # print 'saving file : ', fn f_out = h5py.File('%s%s.hdf5'%(pathf, filename), 'w') f_out.create_dataset('PILenegy', data = pil_energy_v) f_out.create_dataset('Ph Offset', data = self.phase_offset) f_out.create_dataset('Scan', data = self.dati_scan) f_out.close() # return '%s%s.hdf5'%(dn, fn) ##################### if __name__ == '__main__': app = QApplication([]) window = MainWindow() window.show() sys.exit(app.exec_())