Initial Commit

This commit is contained in:
2025-04-25 16:02:46 +02:00
committed by Sven
parent c30fedabeb
commit 68e39be725
8 changed files with 4383 additions and 0 deletions

25
OpticsMachine.py Normal file
View File

@@ -0,0 +1,25 @@
import re
import sys
from typing import is_typeddict
sys.path.append('/sf/bd/packages/sfbd')
from sfbd.interface import getSnapPV,getSnapVal
from epics import PV
class Machine:
def __init__(self):
print('Initializing PVs for Snapshot...')
mags = ['SINLH02-MBND100', 'SINBC02-MBND100', 'S10BC02-MBND100', 'SARCL02-MBND100', 'SATCL01-MBND100',
'SATUN05-MBND100']
self.snapPVs = getSnapPV() + [PV('%s:ENERGY-OP' % ele, auto_monitor=False) for ele in mags]
self.omfilter = ['.*-RMSM:SM-SET','.*-RSYS:REQUIRED-OP','.*-RSYS:SET-ACC-VOLT','.*-RSYS:SET-BEAM-PHASE']
def getSnap(self,filters = ['.*']):
if isinstance(filters, str):
filters = [filters]
recomp = re.compile('|'.join(filters))
pvget = [pv for pv in self.snapPVs if recomp.match(pv.pvname)]
self.snap = getSnapVal(pvget)

36
OpticsModel.py Normal file
View File

@@ -0,0 +1,36 @@
import sys
import numpy as np
sys.path.append('/sf/bd/packages/onlinemodel')
from onlinemodel.core import Facility
from onlinemodel.code import MadX
class Model:
def __init__(self, phase, debug=False):
print('Initializing online model ...')
self.phase = phase # current planned future
self.om = Facility(phase)
self.madx = MadX()
self.twiss = None
def update(self, snap) -> None:
self.om.updateModel(snap,True)
def track(self, start,end,twiss):
destination = 'ARAMIS'
start0 = start[0:7]
end0 = end[0:7]
if 'SPO' in end:
destination = 'PORTHOS'
elif 'SAT' in end:
destination = 'ATHOS'
elif 'S10BD' in end:
destination = 'INJECTOR'
self.om.setBranch(destination,start0,end0)
self.madx.setInitialCondition(twiss['betax'],twiss['betay'],twiss['alphax'],twiss['alphay'],150.)
if len(start) <8:
start = '#s'
if len(end) < 8:
end = '#e'
self.madx.track(self.om,False,start,end)
self.twiss = self.madx.getTwiss()

158
OpticsPlotting.py Normal file
View File

@@ -0,0 +1,158 @@
#!/opt/gfa/python-3.5/latest/bin/python
import sys
import datetime
import os.path
import time
from os import walk
import numpy as np
import sys
import re
from matplotlib.figure import Figure
import matplotlib.patches as patches
from matplotlib.backends.backend_qt5agg import (
FigureCanvasQTAgg as FigureCanvas,
NavigationToolbar2QT as NavigationToolbar)
class OpticsPlotting:
def initmpl(self,mplvl,mplwindow):
self.fig=Figure()
self.axes=self.fig.add_subplot(111)
self.axes2 = self.axes.twinx()
self.canvas = FigureCanvas(self.fig)
mplvl.addWidget(self.canvas)
self.canvas.draw()
self.toolbar=NavigationToolbar(self.canvas,mplwindow, coordinates=True)
mplvl.addWidget(self.toolbar)
def plotSingle(self,x,y,color,legend,dashed=False):
if dashed:
self.axes.plot(x,y,'--',color=color,label=legend)
else:
self.axes.plot(x,y,color=color,label=legend)
def plot(self,data,filt,z0,z1):
self.axes.clear()
self.axes2.clear()
s=np.array(data['S'])
if z0>z1:
tmp=z1
z1=z0
z0=tmp
i1=np.argmin(np.abs(s-z0))
i2=np.argmin(np.abs(s-z1))
ylabel=r''
if filt['BETX']:
self.plotSingle(s[i1:i2],data['BETX'][i1:i2],(0,0,1,1),r'$\beta_{x}$')
ylabel=ylabel+r'$\beta_x$ (m), '
if filt['BETY']:
self.plotSingle(s[i1:i2],data['BETY'][i1:i2],(1,0,0,1),r'$\beta_{y}$')
ylabel=ylabel+r'$\beta_y$ (m), '
if filt['ALFX']:
self.plotSingle(s[i1:i2],data['ALFX'][i1:i2],(0,0,1,1),r'$\alpha_{x}$')
ylabel=ylabel+r'$\alpha_x$ (rad), '
if filt['ALFY']:
self.plotSingle(s[i1:i2],data['ALFY'][i1:i2],(1,0,0,1),r'$\alpha_{y}$')
ylabel=ylabel+r'$\alpha_y$ (rad), '
if filt['DX']:
self.plotSingle(s[i1:i2],data['DX'][i1:i2],(0,0,1,1),r'$\eta_{x}$')
ylabel=ylabel+r'$\eta_x$ (m), '
if filt['DY']:
self.plotSingle(s[i1:i2],data['DY'][i1:i2],(1,0,0,1),r'$\eta_{y}$')
ylabel=ylabel+r'$\eta_y$ (m), '
if filt['RE56']:
self.plotSingle(s[i1:i2],data['RE56'][i1:i2],(0,0,0,1),r'$R_{56}$')
ylabel=ylabel+r'$R_{56}$ (m), '
if filt['Energy']:
self.plotSingle(s[i1:i2],data['Energy'][i1:i2],(0,1,0,1),r'$E$')
ylabel=ylabel+r'$E$ (MeV), '
if len(ylabel) < 3:
self.canvas.draw()
return
self.axes.legend(bbox_to_anchor=(0.15,0.85))
self.axes.set_xlabel('s (m)')
self.axes.set_ylabel(ylabel[0:-2])
self.plotLayout(s,data['NAME'])
self.axes.set_xlim([s[i1],s[i2]])
ylim=self.axes.get_ylim()
dl=np.abs(ylim[1]-ylim[0])
yl=[ylim[0],ylim[1]+0.2*dl]
self.axes.set_ylim(yl)
self.axes2.set_xlim([s[i1],s[i2]])
self.canvas.draw()
return
def plotLayout(self,s,elements):
splitquads=False
sstart=0
s1=[np.min(s),np.max(s)]
s2=[0.9,0.9]
self.axes2.plot(s1,s2,'k')
for i,name in enumerate(elements):
if 'MBND' in name:
s1=s[i-1]
s2=s[i]
self.axes2.add_patch(patches.Rectangle((s1, 0.9), (s2-s1),0.03,facecolor='blue',edgecolor="none"))
if 'MSEX' in name:
s1=s[i-1]
s2=s[i]
self.axes2.add_patch(patches.Rectangle((s1, 0.87), (s2-s1),0.06,facecolor='green',edgecolor="none"))
if 'UIND' in name:
s1=s[i-1]
s2=s[i]
self.axes2.add_patch(patches.Rectangle((s1, 0.88), (s2-s1),0.04,facecolor='purple',edgecolor="none"))
if 'ACC' in name or 'TDS' in name:
s1=s[i-1]
s2=s[i]
self.axes2.add_patch(patches.Rectangle((s1, 0.89), (s2-s1),0.02,facecolor='cyan',edgecolor="none"))
if 'MQUA' in name:
if splitquads == True:
if 'END' in name:
s1=sstart
s2=s[i]
self.axes2.add_patch(patches.Rectangle((s1, 0.85), (s2-s1),0.1,facecolor='red',edgecolor="none"))
splitquads=False
else:
if 'START' in name:
splitquads=True
sstart=s[i]
else:
s1=s[i-1]
s2=s[i]
self.axes2.add_patch(patches.Rectangle((s1, 0.85), (s2-s1),0.1,facecolor='red',edgecolor="none"))
self.axes2.set_ylim([0,1])
self.axes2.yaxis.set_visible(False)
return
#

131
OpticsTools.py Normal file
View File

@@ -0,0 +1,131 @@
import sys
#import re
#import numpy as np
#import copy
#import os
#import json
from datetime import datetime
import time
#from shutil import copyfile
#from os.path import isfile, join
from PyQt5 import QtWidgets,QtGui
from PyQt5.uic import loadUiType
#from PyQt5.QtGui import QPixmap, QTransform
#from PyQt5.QtWidgets import QMessageBox
from ui.OpticsToolsGui import Ui_OpticsGUI
from OpticsModel import Model
from OpticsMachine import Machine
from OpticsPlotting import OpticsPlotting
class OpticsTools(QtWidgets.QMainWindow, Ui_OpticsGUI):
def __init__(self,phase=0):
super(OpticsTools, self).__init__()
self.setupUi(self)
self.version = '1.0.1'
self.setWindowIcon(QtGui.QIcon("rsc/iconoptics.png"))
self.setWindowTitle("SwissFEL Optics Tools")
self.plot = OpticsPlotting()
self.plot.initmpl(self.mplvl, self.mplwindow)
# initialize online model
self.model = Model(phase)
if phase == 0:
self.machine = Machine()
else:
self.machine = None
# widget signals
self.UITrack.clicked.connect(self.track)
# all action for optics plotting
self.PBetax.toggled.connect(self.doplot)
self.PAlphax.toggled.connect(self.doplot)
self.PBetay.toggled.connect(self.doplot)
self.PAlphay.toggled.connect(self.doplot)
self.PEtax.toggled.connect(self.doplot)
self.PEtay.toggled.connect(self.doplot)
self.PR56.toggled.connect(self.doplot)
# self.PEnergy.toggled.connect(self.doplot)
self.PStart.editingFinished.connect(self.doplot)
self.PEnd.editingFinished.connect(self.doplot)
def track(self):
start = str(self.UITrackStart.text())
end = str(self.UITrackEnd.text())
twiss = {}
twiss['betax'] = float(str(self.UIBetax.text()))
twiss['betay'] = float(str(self.UIBetay.text()))
twiss['alphax'] = float(str(self.UIAlphax.text()))
twiss['alphay'] = float(str(self.UIAlphay.text()))
self.model.track(start,end,twiss)
self.updateOpticsTable()
def updateOpticsTable(self):
self.UITwissValues.clear()
if self.model.twiss is None:
return
res = self.model.twiss
if 'NAME' in res.keys():
nrow = len(res['NAME'])
if nrow == 0:
return
else:
return
ncol = len(res.keys())
self.UITwissValues.setColumnCount(ncol + 1)
self.UITwissValues.setRowCount(nrow)
for j,key in enumerate(res.keys()):
col = res[key]
self.UITwissValues.setHorizontalHeaderItem(j, QtWidgets.QTableWidgetItem(key))
for i,val in enumerate(col):
if j == 0:
self.UITwissValues.setItem(i, j, QtWidgets.QTableWidgetItem(val))
else:
self.UITwissValues.setItem(i, j, QtWidgets.QTableWidgetItem('%10.6f' % val))
self.UITwissValues.resizeColumnsToContents()
self.UITwissValues.verticalHeader().hide()
self.UITwissValues.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
def doplot(self):
if self.model.twiss is None:
return
zstart=float(str(self.PStart.text()))
zend=float(str(self.PEnd.text()))
filt={}
filt['BETX']=self.PBetax.isChecked()
filt['BETY']=self.PBetay.isChecked()
filt['ALFX']=self.PAlphax.isChecked()
filt['ALFY']=self.PAlphay.isChecked()
filt['DX']=self.PEtax.isChecked()
filt['DY']=self.PEtay.isChecked()
filt['RE56']=self.PR56.isChecked()
filt['Energy']=self.PEnergy.isChecked()
self.plot.plot(self.model.twiss,filt,zstart,zend)
# --------------------------------
# Main routine
if __name__ == '__main__':
QtWidgets.QApplication.setStyle(QtWidgets.QStyleFactory.create("plastique"))
app = QtWidgets.QApplication(sys.argv)
if len(sys.argv) > 1:
arg=int(sys.argv[1])
else:
arg=0
main = OpticsTools()
main.show()
sys.exit(app.exec_())

BIN
rsc/iconoptics.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

1440
ui/OpticsToolsGui.py Normal file

File diff suppressed because it is too large Load Diff

2591
ui/OpticsToolsGui.ui Normal file

File diff suppressed because it is too large Load Diff

2
updateGui.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
pyuic5 ui/OpticsToolsGui.ui > ui/OpticsToolsGui.py