From 58870221e20098e42b7402db3639cc13e7aa8d9f Mon Sep 17 00:00:00 2001 From: "mauro.trovo" <mauro.trovo@elettra.eu> Date: Mon, 7 Sep 2020 17:52:30 +0200 Subject: [PATCH] MT - origin file --- gunPhaseScan.py | 390 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 390 insertions(+) create mode 100644 gunPhaseScan.py diff --git a/gunPhaseScan.py b/gunPhaseScan.py new file mode 100644 index 0000000..338a245 --- /dev/null +++ b/gunPhaseScan.py @@ -0,0 +1,390 @@ +#!/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_()) -- GitLab