From aa0cf00664887cdb5a867de0429ab343da21d6c9 Mon Sep 17 00:00:00 2001 From: reiche Date: Thu, 8 May 2025 15:08:21 +0200 Subject: [PATCH] Some further debugging and some nice optics --- issues.txt | 5 +-- matching.py | 3 +- matchingmanager.py | 1 + model.py | 78 ++++++++++++++++++++++------------- plot.py | 16 ++++++-- ui/OpticsPlotGui.py | 54 +++++++++++++++---------- ui/OpticsPlotGui.ui | 96 ++++++++++++++++++++++++++------------------ ui/OpticsToolsGui.py | 3 ++ ui/OpticsToolsGui.ui | 3 ++ 9 files changed, 162 insertions(+), 97 deletions(-) diff --git a/issues.txt b/issues.txt index ca3cc90..afcf4cc 100644 --- a/issues.txt +++ b/issues.txt @@ -6,10 +6,7 @@ 6) matching 7) when writing magnets do snapshot? 8) Elegant support? -9) initial beta-function saved, also to settings file 10) Prepare several settings files 11) About and website support 12) install cpymax on machine network -13) save/load settings : Initial energy and initial twiss -14) right energy for tracking -15) set initial condition for tracking cpymadx + diff --git a/matching.py b/matching.py index 93c76c8..cf54b2d 100644 --- a/matching.py +++ b/matching.py @@ -18,7 +18,8 @@ class Matching: vals = [-val for val in vals] var = {name:vals[i] for i,name in enumerate(quads)} cond = {'range':'#e','mux':par['mu'],'muy':par['mu']} - twiss,tar = self.model.match(sequence=par['Sequence'], destination=par['Destination'],variables=var, conditions=cond, periodic=True) + res,twiss,tar = self.model.match(sequence=par['Sequence'], destination=par['Destination'],variables=var, conditions=cond, periodic=True) par['Result']=tar par['Twiss']=twiss + print(res) self.manager.setFODOParameters(par) diff --git a/matchingmanager.py b/matchingmanager.py index 6c3c5be..6772a7e 100644 --- a/matchingmanager.py +++ b/matchingmanager.py @@ -46,6 +46,7 @@ class MatchManager: print('Not Supported') return None self.FODO[reference]=par + self.updateFODOWidget() def getFODOParameters(self): reference = self.parent.UIMFodoList.currentText() diff --git a/model.py b/model.py index d6bbcd3..099d52a 100644 --- a/model.py +++ b/model.py @@ -1,9 +1,15 @@ import json import copy import numpy as np + from onlinemodel.core import Facility from onlinemodel.madx import CMadX +converttwiss= {'betax':'betx','betay':'bety','alphax':'alfx','alphay':'alfy', + 'etax':'dx','etay':'dy','etapx':'dpx','etapy':'dpy', + 'x':'x','y':'y','px':'px','py':'py','energy':'energy'} + + class Model: def __init__(self, phase=0, parent=None): print('Initializing online model ...') @@ -76,7 +82,6 @@ class Model: undulators={} kicker={} energy={'location': self.energyReference, 'energy' : 1e-6*self.om.EnergyAt(self.energyReference)[0]} - for ele in elements: if 'MQUA' in ele.Name or 'MQSK' in ele.Name: quadrupoles[ele.Name]={'k1':ele.k1,'k1L':ele.k1*ele.Length} @@ -94,24 +99,30 @@ class Model: return {'Quadrupole':quadrupoles,'Sextupole':sextupoles,'Dipole':dipoles,'RF':rf,'Undulator':undulators, 'Kicker':kicker,'Energy':energy, 'InitialCondition':self.startTwiss} - def loadSettingsGroup(self,group,fields): + def loadSettingsGroup(self,group,fields,normalized=False): for key in group.keys(): ele = self.om.getElement(key) for field in fields: ele.__dict__[field]=group[key][field] + if normalized: + ele.__dict__[field]/=ele.Length def loadSettings(self,settings): self.loadSettingsGroup(settings['Quadrupole'],['k1']) self.loadSettingsGroup(settings['Sextupole'], ['k2']) self.loadSettingsGroup(settings['Dipole'], ['angle']) - self.loadSettingsGroup(settings['RF'], ['Gradient','Phase']) + self.loadSettingsGroup(settings['RF'], ['Gradient'],normalized=True) + self.loadSettingsGroup(settings['RF'], ['Phase']) self.loadSettingsGroup(settings['Undulator'], ['K','kx','ky']) self.loadSettingsGroup(settings['Kicker'], ['cory']) self.startEnergy = settings['Energy']['energy'] self.energyReference = settings['Energy']['location'] self.startTwiss = settings['InitialCondition'] - print('initial condition:',self.startTwiss) + print(self.startTwiss) self.updateEnergy(self.startEnergy) + print(settings['Energy']['energy']) + print('Energy in system',self.om.EnergyAt(self.energyReference)[0]) + @@ -130,6 +141,7 @@ class Model: elif 'K2L' == fld: ele.k2 = data['settings'][key]/ele.Length elif 'Grad' == fld: +# ele.Gradient = data['settings'][key]/ele.Length ele.Gradient = data['settings'][key] elif 'Phase' == fld: ele.Phase = data['settings'][key] @@ -162,10 +174,10 @@ class Model: self.madx.updateVariables(twiss) res,twiss,tar=self.madx.match(sequence,variables,conditions,periodic) energy = self.calcEnergyProfile(twiss) - matchtwiss={'betax':twiss.betx[0],'betay':twiss.betay[0],'alphax':twiss.alfx[0],'alphay':twiss.alfy[0]} + matchtwiss={'betax':twiss.betx[0],'betay':twiss.bety[0],'alphax':twiss.alfx[0],'alphay':twiss.alfy[0]} if plot: self.parent.plot.newData(twiss, energy) - return matchtwiss,tar + return res, matchtwiss,tar def track(self): @@ -179,7 +191,8 @@ class Model: refloc = self.parent.reference.getReferenceLocation().upper() if refloc == 'START': refloc = start.upper() - twiss0['energy'] = self.startEnergy + twiss0['energy'] = self.startEnergy*1e-3 # convert to GeV for madx + start, end = self.checkRange(start, end, refloc[0:7]) if start is None: return @@ -188,13 +201,16 @@ class Model: def doTrack(self, start,end, refloc, twiss_in, plot = True): - twiss0={key+'0':twiss_in[key] for key in twiss_in.keys()} + twiss0 = {converttwiss[key]:twiss_in[key] for key in twiss_in.keys()} self.setBranch(end.upper()) if not refloc == start: twiss0 = self.doBackTrack(refloc,start,twiss0) - self.startTwiss=copy.deepcopy(twiss0) + print('Back Tracking Done') + for key in twiss_in.keys(): + if converttwiss[key] in twiss0.keys(): + self.startTwiss[key+'0'] = twiss0[converttwiss[key]] self.madx.updateVariables(twiss0) - twiss = self.madx.track(start+'$START',end+'$END') + twiss = self.madx.track('swissfel',start+'$START',end+'$END') energy = self.calcEnergyProfile(twiss) if plot: self.parent.plot.newData(twiss,energy) @@ -217,27 +233,29 @@ class Model: def doBackTrack(self,start=None,end=None,twiss0=None): - twiss0['alphax0'] = -twiss0['alphax0'] # revert particle trajectories - twiss0['alphay0'] = -twiss0['alphay0'] - twiss0['etapx0'] = -twiss0['etapx0'] - twiss0['etapy0'] = -twiss0['etapx0'] - twiss0['px0'] = -twiss0['px0'] - twiss0['py0'] = -twiss0['py0'] + print('Backtracking 1:',twiss0) + twiss0['alfx'] = -twiss0['alfx'] # revert particle trajectories + twiss0['alfy'] = -twiss0['alfy'] + twiss0['dpx'] = -twiss0['dpx'] + twiss0['dpy'] = -twiss0['dpy'] + twiss0['px'] = -twiss0['px'] + twiss0['py'] = -twiss0['py'] self.madx.updateVariables(twiss0) - twiss = self.madx.track(start, end+'$START', reverse=True) + print(start,end) + twiss = self.madx.track('invswissfel', start, end+'$START') twiss1 = {} - twiss1['betax0'] = twiss.betx[-1] # revert trajectory back - twiss1['betay0'] = twiss.bety[-1] - twiss1['alphax0'] = -twiss.alfx[-1] - twiss1['alphay0'] = -twiss.alfy[-1] - twiss1['etax0'] = twiss.dx[-1] - twiss1['etay0'] = twiss.dy[-1] - twiss1['etapx0'] = -twiss.dpx[-1] - twiss1['etapy0'] = -twiss.dpy[-1] - twiss1['x0'] = twiss.x[-1] - twiss1['y0'] = twiss.y[-1] - twiss1['px0'] = -twiss.px[-1] - twiss1['py0'] = -twiss.py[-1] + twiss1['betx'] = twiss.betx[-1] # revert trajectory back + twiss1['bety'] = twiss.bety[-1] + twiss1['alfx'] = -twiss.alfx[-1] + twiss1['alfy'] = -twiss.alfy[-1] + twiss1['dx'] = twiss.dx[-1] + twiss1['dy'] = twiss.dy[-1] + twiss1['dpx'] = -twiss.dpx[-1] + twiss1['dpy'] = -twiss.dpy[-1] + twiss1['x'] = twiss.x[-1] + twiss1['y'] = twiss.y[-1] + twiss1['px'] = -twiss.px[-1] + twiss1['py'] = -twiss.py[-1] return twiss1 def setBranch(self,end): @@ -276,3 +294,5 @@ class Model: end = ref print('Reference point is downstream the tracking range. Extending range') return start,end + + diff --git a/plot.py b/plot.py index a36d5a8..1370555 100644 --- a/plot.py +++ b/plot.py @@ -78,6 +78,8 @@ class OpticsPlot(QtWidgets.QMainWindow, Ui_OpticsPlotGUI): data['etax'] = np.array(self.twiss.dx) data['etay'] = np.array(self.twiss.dy) data['r56'] = np.array(self.twiss.re56) + data['mux'] = np.array(self.twiss.mux) + data['muy'] = np.array(self.twiss.muy) data['x'] = np.array(self.twiss.x) data['y'] = np.array(self.twiss.y) data['energy'] = np.array(self.energy) @@ -109,10 +111,10 @@ class OpticsPlot(QtWidgets.QMainWindow, Ui_OpticsPlotGUI): return nrow = len(self.twiss.s) - ncol = 10 + ncol = 12 self.UITwissValues.setColumnCount(ncol) self.UITwissValues.setRowCount(nrow) - self.UITwissValues.setHorizontalHeaderLabels(['Name','s','betax','betay','alphax','alphay','etax','etay','r56','energy']) + self.UITwissValues.setHorizontalHeaderLabels(['Name','s','betax','betay','alphax','alphay','etax','etay','r56','mux','muy','energy']) for i in range(nrow): self.UITwissValues.setItem(i, 0, QtWidgets.QTableWidgetItem(self.twiss.name[i].split(':')[0])) self.UITwissValues.setItem(i, 1, QtWidgets.QTableWidgetItem('%10.6f' % self.twiss.s[i])) @@ -123,7 +125,9 @@ class OpticsPlot(QtWidgets.QMainWindow, Ui_OpticsPlotGUI): self.UITwissValues.setItem(i, 6, QtWidgets.QTableWidgetItem('%10.6f' % self.twiss.dx[i])) self.UITwissValues.setItem(i, 7, QtWidgets.QTableWidgetItem('%10.6f' % self.twiss.dy[i])) self.UITwissValues.setItem(i, 8, QtWidgets.QTableWidgetItem('%10.6f' % self.twiss.re56[i])) - self.UITwissValues.setItem(i, 9, QtWidgets.QTableWidgetItem('%10.6f' % self.energy[i])) + self.UITwissValues.setItem(i, 9, QtWidgets.QTableWidgetItem('%10.6f' % self.twiss.mux[i])) + self.UITwissValues.setItem(i,10, QtWidgets.QTableWidgetItem('%10.6f' % self.twiss.muy[i])) + self.UITwissValues.setItem(i,11, QtWidgets.QTableWidgetItem('%10.6f' % self.energy[i])) self.UITwissValues.resizeColumnsToContents() self.UITwissValues.verticalHeader().hide() self.UITwissValues.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) @@ -150,6 +154,8 @@ class OpticsPlot(QtWidgets.QMainWindow, Ui_OpticsPlotGUI): filt['DY']=self.PEtay.isChecked() filt['RE56']=self.PR56.isChecked() filt['Energy']=self.PEnergy.isChecked() + filt['MUX'] = self.PMux.isChecked() + filt['MUY'] = self.PMuy.isChecked() s = self.twiss.s i1 = np.argmin(np.abs(s - z0)) @@ -177,6 +183,10 @@ class OpticsPlot(QtWidgets.QMainWindow, Ui_OpticsPlotGUI): if filt['DY']: self.plotSingle(s[i1:i2], self.twiss.dy[i1:i2], (1, 0, 0, 1), r'$\eta_{y}$') ylabel = ylabel + r'$\eta_y$ (m), ' + if filt['MUX']: + self.plotSingle(s[i1:i2], self.twiss.mux[i1:i2], (0, 0.5, 1, 1), r'$\mu_{y}$') + if filt['MUY']: + self.plotSingle(s[i1:i2], self.twiss.muy[i1:i2], (1, 0.5, 0, 1), r'$\mu_{y}$') if filt['RE56']: self.plotSingle(s[i1:i2], self.twiss.re56[i1:i2], (0, 0, 0, 1), r'$R_{56}$') ylabel = ylabel + r'$R_{56}$ (m), ' diff --git a/ui/OpticsPlotGui.py b/ui/OpticsPlotGui.py index 1811a78..dd6cc33 100644 --- a/ui/OpticsPlotGui.py +++ b/ui/OpticsPlotGui.py @@ -44,19 +44,6 @@ class Ui_OpticsPlotGUI(object): self.PBetax.setChecked(True) self.PBetax.setObjectName("PBetax") self.gridLayout_4.addWidget(self.PBetax, 0, 0, 1, 1) - self.PBetay = QtWidgets.QPushButton(self.widget_2) - self.PBetay.setCheckable(True) - self.PBetay.setChecked(True) - self.PBetay.setObjectName("PBetay") - self.gridLayout_4.addWidget(self.PBetay, 0, 1, 1, 1) - self.PAlphax = QtWidgets.QPushButton(self.widget_2) - self.PAlphax.setCheckable(True) - self.PAlphax.setObjectName("PAlphax") - self.gridLayout_4.addWidget(self.PAlphax, 1, 0, 1, 1) - self.PAlphay = QtWidgets.QPushButton(self.widget_2) - self.PAlphay.setCheckable(True) - self.PAlphay.setObjectName("PAlphay") - self.gridLayout_4.addWidget(self.PAlphay, 1, 1, 1, 1) self.PEtax = QtWidgets.QPushButton(self.widget_2) self.PEtax.setCheckable(True) self.PEtax.setObjectName("PEtax") @@ -65,15 +52,36 @@ class Ui_OpticsPlotGUI(object): self.PEtay.setCheckable(True) self.PEtay.setObjectName("PEtay") self.gridLayout_4.addWidget(self.PEtay, 2, 1, 1, 1) - self.PR56 = QtWidgets.QPushButton(self.widget_2) - self.PR56.setCheckable(True) - self.PR56.setObjectName("PR56") - self.gridLayout_4.addWidget(self.PR56, 3, 0, 1, 1) self.PEnergy = QtWidgets.QPushButton(self.widget_2) self.PEnergy.setEnabled(True) self.PEnergy.setCheckable(True) self.PEnergy.setObjectName("PEnergy") - self.gridLayout_4.addWidget(self.PEnergy, 3, 1, 1, 1) + self.gridLayout_4.addWidget(self.PEnergy, 4, 1, 1, 1) + self.PAlphay = QtWidgets.QPushButton(self.widget_2) + self.PAlphay.setCheckable(True) + self.PAlphay.setObjectName("PAlphay") + self.gridLayout_4.addWidget(self.PAlphay, 1, 1, 1, 1) + self.PR56 = QtWidgets.QPushButton(self.widget_2) + self.PR56.setCheckable(True) + self.PR56.setObjectName("PR56") + self.gridLayout_4.addWidget(self.PR56, 4, 0, 1, 1) + self.PAlphax = QtWidgets.QPushButton(self.widget_2) + self.PAlphax.setCheckable(True) + self.PAlphax.setObjectName("PAlphax") + self.gridLayout_4.addWidget(self.PAlphax, 1, 0, 1, 1) + self.PBetay = QtWidgets.QPushButton(self.widget_2) + self.PBetay.setCheckable(True) + self.PBetay.setChecked(True) + self.PBetay.setObjectName("PBetay") + self.gridLayout_4.addWidget(self.PBetay, 0, 1, 1, 1) + self.PMux = QtWidgets.QPushButton(self.widget_2) + self.PMux.setCheckable(True) + self.PMux.setObjectName("PMux") + self.gridLayout_4.addWidget(self.PMux, 3, 0, 1, 1) + self.PMuy = QtWidgets.QPushButton(self.widget_2) + self.PMuy.setCheckable(True) + self.PMuy.setObjectName("PMuy") + self.gridLayout_4.addWidget(self.PMuy, 3, 1, 1, 1) self.verticalLayout_5.addLayout(self.gridLayout_4) self.gridLayout_5 = QtWidgets.QGridLayout() self.gridLayout_5.setObjectName("gridLayout_5") @@ -274,13 +282,15 @@ class Ui_OpticsPlotGUI(object): OpticsPlotGUI.setWindowTitle(_translate("OpticsPlotGUI", "SwissFEL Optics")) self.label_31.setText(_translate("OpticsPlotGUI", "Plotting")) self.PBetax.setText(_translate("OpticsPlotGUI", "Betax")) - self.PBetay.setText(_translate("OpticsPlotGUI", "Betay")) - self.PAlphax.setText(_translate("OpticsPlotGUI", "Alphax")) - self.PAlphay.setText(_translate("OpticsPlotGUI", "AlphaY")) self.PEtax.setText(_translate("OpticsPlotGUI", "Etax")) self.PEtay.setText(_translate("OpticsPlotGUI", "Etay")) - self.PR56.setText(_translate("OpticsPlotGUI", "R56")) self.PEnergy.setText(_translate("OpticsPlotGUI", "Energy")) + self.PAlphay.setText(_translate("OpticsPlotGUI", "AlphaY")) + self.PR56.setText(_translate("OpticsPlotGUI", "R56")) + self.PAlphax.setText(_translate("OpticsPlotGUI", "Alphax")) + self.PBetay.setText(_translate("OpticsPlotGUI", "Betay")) + self.PMux.setText(_translate("OpticsPlotGUI", "Mux")) + self.PMuy.setText(_translate("OpticsPlotGUI", "Muy")) self.label_22.setText(_translate("OpticsPlotGUI", "Plot Start")) self.PStart.setText(_translate("OpticsPlotGUI", "0")) self.label_21.setText(_translate("OpticsPlotGUI", "Plot End")) diff --git a/ui/OpticsPlotGui.ui b/ui/OpticsPlotGui.ui index 3b8c560..78cb7c8 100644 --- a/ui/OpticsPlotGui.ui +++ b/ui/OpticsPlotGui.ui @@ -56,39 +56,6 @@ - - - - Betay - - - true - - - true - - - - - - - Alphax - - - true - - - - - - - AlphaY - - - true - - - @@ -109,7 +76,30 @@ - + + + + true + + + Energy + + + true + + + + + + + AlphaY + + + true + + + + R56 @@ -119,13 +109,43 @@ - - - + + + + Alphax + + true + + + + - Energy + Betay + + + true + + + true + + + + + + + Mux + + + true + + + + + + + Muy true diff --git a/ui/OpticsToolsGui.py b/ui/OpticsToolsGui.py index d15c59d..5a01f7f 100644 --- a/ui/OpticsToolsGui.py +++ b/ui/OpticsToolsGui.py @@ -429,6 +429,9 @@ class Ui_OpticsGUI(object): spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.verticalLayout_5.addItem(spacerItem2) self.horizontalLayout_7.addLayout(self.verticalLayout_5) + self.UIMatchLog = QtWidgets.QPlainTextEdit(self.tab) + self.UIMatchLog.setObjectName("UIMatchLog") + self.horizontalLayout_7.addWidget(self.UIMatchLog) spacerItem3 = QtWidgets.QSpacerItem(380, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_7.addItem(spacerItem3) self.TabMaster.addTab(self.tab, "") diff --git a/ui/OpticsToolsGui.ui b/ui/OpticsToolsGui.ui index 211ff92..d7c8579 100644 --- a/ui/OpticsToolsGui.ui +++ b/ui/OpticsToolsGui.ui @@ -752,6 +752,9 @@ + + +