from dataclasses import field from PyQt5 import QtCore, QtGui, QtWidgets import numpy as np import re import scipy import json CGrey = QtGui.QColor(230,230,230) CBeige = QtGui.QColor(250, 240, 200) CGreen = QtGui.QColor(100, 255, 100) CYellow = QtGui.QColor(255, 255, 0) CRed = QtGui.QColor(255, 100, 100) CWhite = QtGui.QColor(255, 255, 255) class Sandbox: def __init__(self, parent=None,machine=False): self.parent=parent self.machine=machine self.parent.MagReStart.editingFinished.connect(self.updateSandbox) self.parent.MagReFilter.editingFinished.connect(self.updateSandbox) self.parent.Mach2ModMag.clicked.connect(self.updateModelEvent) self.parent.SB2ModMag.clicked.connect(self.updateModelEvent) self.parent.Mach2ModUnd.clicked.connect(self.updateModelEvent) self.parent.SB2ModUnd.clicked.connect(self.updateModelEvent) self.parent.SB2MachineMag.clicked.connect(self.updateMachine) self.parent.SBLongTrack.clicked.connect(self.updateFromLongTrack) def updateMachine(self): vals = self.getSBbyCol(self.parent.MagSB,1) self.parent.machine.setMagnets(vals) self.updateSandbox() def getSBbyCol(self, sb,col): vals={} for i in range(sb.rowCount()): field=str(sb.item(i,0).text()) val = str(sb.item(i, col).text()) if val == '---': continue vals[field]=float(val) return vals def updateModelEvent(self): if self.parent.sender() is self.parent.Mach2ModMag: print('Update Magnets from Machine') self.updateModel(self.parent.MagSB,2,True) elif self.parent.sender() is self.parent.SB2ModMag: print('Update Magnets from Sandbox') self.updateModel(self.parent.MagSB, 1, True) elif self.parent.sender() is self.parent.Mach2ModUnd: self.updateModel(self.parent.UndSB, 3, False) self.updateModel(self.parent.RFSB, 3, False) energy= float(str(self.parent.SBE0Machine.text())) print('Updating from Maching:',energy) self.parent.model.updateEnergy(energy) elif self.parent.sender() is self.parent.SB2ModUnd: self.updateModel(self.parent.UndSB, 1, False) self.updateModel(self.parent.RFSB, 1, False) energy = float(str(self.parent.SBE0Model.text())) print('Updating from Model:',energy) self.parent.model.updateEnergy(energy) self.updateSandbox() self.parent.model.forceLatticeUpdate() self.parent.status('Sandbox mode') def updateModel(self,sb,col,single): for i in range(sb.rowCount()): field=str(sb.item(i,0).text()) val = str(sb.item(i, col).text()) if val == '---': continue if single: val = [val] else: val = [val,str(sb.item(i,col+1).text())] self.parent.model.updateElement(field.replace('-','.'),val) def updateSandbox(self): machine = self.parent.machine.getMachineStatus() model = self.parent.model.getSettings() self.updateMagSandbox(self.parent.MagSB,model,machine['Magnet']) self.updateUndSandbox(self.parent.UndSB,model,machine['Undulator']) self.updateRFSandbox(self.parent.RFSB, model, machine['RF']) self.updateEnergySandbox(model['Energy'],machine['Energy']) def updateEnergySandbox(self,model,machine): E0=model['energy'] self.parent.SBE0Model.setText('%7.3f' % E0) E0 = None for key in machine.keys(): E0 = machine[key] if E0 is None: self.parent.SBE0Machine.setText("---") else: self.parent.SBE0Machine.setText('%7.3f' % E0) def updateSandboxCommon(self,sb,values,colors,labels): sb.clear() ncol = len(labels) nrow = len(values) sb.setColumnCount(ncol) sb.setRowCount(nrow) for i in range(ncol): sb.setHorizontalHeaderItem(i, QtWidgets.QTableWidgetItem(labels[i])) for irow,value in enumerate(values): color=colors[irow] for icol in range(ncol): sb.setItem(irow, icol, QtWidgets.QTableWidgetItem(value[icol])) sb.item(irow, icol).setBackground(color[icol]) sb.resizeColumnsToContents() sb.verticalHeader().hide() def updateRFSandbox(self,sb,model,machine): labels = ['Station', 'Model', 'Model', 'Machine', 'Machine'] values = [] colors = [] for key in machine.keys(): sbvalue = [key[0:7]+'-RSYS'] sbcolor = [CWhite] mokey = key[0:7]+'.RACC100' scl=1. if 'CB' in mokey: scl = 4 elif 'SINSB03' in mokey or 'SINSB04' in mokey or 'SINXB' in mokey: scl = 2 if mokey in model['RF'].keys(): Grad=1e-6*model['RF'][mokey]['Gradient']*scl Phase= model['RF'][mokey]['Phase'] sbvalue+=['%7.3f' % Grad,'%7.3f' % Phase] sbcolor += [CBeige, CBeige] else: sbvalue += ['---', '---'] sbcolor += [CGrey, CGrey] value = machine[key] if value[0] is None: sbvalue += ['---', '---'] sbcolor += [CGrey, CGrey] else: sbvalue += ['%7.3f' % machine[key][0], '%7.3f' % machine[key][1]] sbcolor += [CBeige, CBeige] values.append(sbvalue) colors.append(sbcolor) self.updateSandboxCommon(sb, values, colors, labels) def updateUndSandbox(self,sb,model,machine,): labels = ['Undulator', 'Model', 'Model', 'Machine', 'Machine'] values=[] colors=[] pol = ['LH', 'LV+', 'LV-', 'C+', 'C-', 'ZL'] for key in machine.keys(): sbvalue=[key] sbcolor=[CWhite] mokey = key.replace('-', '.') if 'UMOD' in mokey: if 'SATDI' in mokey: mokey = mokey + '050' else: mokey = mokey + '030' if mokey in model['Undulator'].keys(): value = model['Undulator'][mokey] K = '%7.3f' % value['K'] kx = value['kx'] ky = value['ky'] if np.abs(kx - 1) < 0.1: Pol = 'LV' elif np.abs(ky - 1) < 0.1: Pol = 'LH' elif np.abs(kx - ky) < 0.1: Pol = 'C' else: Pol = 'undef' sbvalue+=[K,Pol] sbcolor+=[CBeige,CBeige] else: sbvalue+=['---','---'] sbcolor+=[CGrey,CGrey] value = machine[key] # machine if value[0] is None: sbvalue +=['---','---'] sbcolor += [CGrey, CGrey] else: sbvalue += ['%7.3f' % value[0], pol[int(value[1])]] sbcolor += [CBeige,CBeige] values.append(sbvalue) colors.append(sbcolor) self.updateSandboxCommon(sb,values,colors,labels) def updateMagSandbox(self,sb,magnets,machine): labels = ['Magnet', 'Model', 'Machine'] filt = str(self.parent.MagReStart.text()) found = False if filt == '' or filt == '*': found = True regpat = re.compile(filt) filt2 = str(self.parent.MagReFilter.text()) filt2 = '.*' + filt2 regpat2 = re.compile(filt2) values = [] colors=[] for key in machine.keys(): if regpat.match(key): found = True if not (found and regpat2.match(key)): continue sbval=[key] sbcol=[CWhite] maval = machine[key] moval=None mokey = key.replace('-','.') if 'MQUA' in key and mokey in magnets['Quadrupole'].keys(): moval = magnets['Quadrupole'][mokey]['k1L'] if 'MQSK' in key and mokey in magnets['Quadrupole'].keys(): moval = magnets['Quadrupole'][mokey]['k1L'] if 'MSEX' in key and mokey in magnets['Sextupole'].keys(): moval = magnets['Sextupole'][mokey]['k2L'] if 'MBND' in key and mokey in magnets['Dipole'].keys(): moval = magnets['Dipole'][mokey]['angle'] if moval is None: # model sbval.append('---') sbcol.append(CGrey) else: sbval.append('%7.3f' % moval) sbcol.append(CBeige) if maval is None: # machine sbval.append('---') sbcol.append(CGrey) else: sbval.append('%7.3f' % maval) if moval is None: sbcol.append(CGrey) else: df = np.abs(moval-maval) if df < 0.001: sbcol.append(CGreen) elif df < 0.01: sbcol.append(CYellow) else: sbcol.append(CRed) values.append(sbval) colors.append(sbcol) self.updateSandboxCommon(sb, values, colors, labels) def updateFromLongTrack(self): options = QtWidgets.QFileDialog.Options() options |= QtWidgets.QFileDialog.DontUseNativeDialog fileName,_ = QtWidgets.QFileDialog.getOpenFileName(self.parent, "Open LongTrack Settings",".","Json Files (*.json)", options=options) if not fileName: return with open(fileName,'r') as f: data = json.load(f) for sec in ['SINSB','SINXB','Linac1-1','Linac1-2','Linac2','Linac3']: self.updateLTRF(data,sec) for sec in ['BC1','BC2','Laser Heater']: self.updateLTBC(data,sec) self.updateSandbox() self.parent.model.forceLatticeUpdate() self.parent.status('Sandbox mode') def updateLTBC(self,data,section): if not section in data.keys(): return self.rootR56=data[section]['R56'] self.rootLb = data[section]['Dipole Length'] self.rootLd = data[section]['L1'] x=data[section]['Angle'] if self.rootR56 > 0: res = scipy.optimize.root_scalar(self.calc56,method='bisect',bracket=[1e-5,0.2]) angle = -res.root*180/np.pi else: angle = 0. if 'BC1' in section: self.parent.model.updateElement('SINBC02.MBND', [angle]) elif 'BC2' in section: self.parent.model.updateElement('S10BC02.MBND', [angle]) elif 'Laser Heater' in section: self.parent.model.updateElement('SINLH02.MBND', [angle]) def calc56(self, x): return 2* (4* x / np.sin(x) * self.rootLb + 2 * self.rootLd / np.cos(x)-4*self.rootLb-2*self.rootLd)-self.rootR56 def updateLTRF(self,data,section): if not section in data.keys(): return phase=data[section]['Phase'] gain=data[section]['Voltage'] if 'Linac3' in section: gain/=13. for i in range(1,14): field='S30CB%2.2d-RSYS' % i val = [gain, phase] self.parent.model.updateElement(field.replace('-', '.'), val) elif 'Linac2' in section: gain/=4 for i in range(1,5): field='S20CB%2.2d-RSYS' % i val = [gain, phase] self.parent.model.updateElement(field.replace('-', '.'), val) elif 'Linac1-2' in section: gain/=7 for i in range(3,10): field='S10CB%2.2d-RSYS' % i val = [gain, phase] self.parent.model.updateElement(field.replace('-', '.'), val) elif 'Linac1-1' in section: gain/=2 for i in range(1,3): field='S10CB%2.2d-RSYS' % i val = [gain, phase] self.parent.model.updateElement(field.replace('-', '.'), val) elif 'SINSB' in section: gain/=2 for i in range(3,5): field='SINSB%2.2d-RSYS' % i val = [gain, phase] self.parent.model.updateElement(field.replace('-', '.'), val) elif 'SINXB' in section: for i in range(1,2): field='SINXB%2.2d-RSYS' % i val = [gain, phase] self.parent.model.updateElement(field.replace('-', '.'), val)