def setResultBox(self, textBox, value): if value is not None: self.valueFromTextBox[textBox] = value textBox.setText(util.displayWithUnitsNumber(util.roundSigFig(value, 5), textBox.unit)) textBox.setCursorPosition(0) else: self.unsetValue(textBox)
def saveToCSV(self, fileName = None): if not fileName: fileName = util.getSaveFileName(self, 'csv') if not fileName: return # make sure the top-level parameters are up-to-date self.designMomentumEV = util.convertUnitsStringToNumber(self.ui.designMomentum.text(), 'eV') self.totalCharge = util.convertUnitsStringToNumber(self.ui.totalCharge.text(), 'C') # create a header to identify this as a RadTrack file h1 = 'RadTrack,Copyright 2012-2014 by RadiaBeam Technologies LLC - All rights reserved (C)\n ' # names of the top-level parameters h2 = 'p0 [eV],Q [C],mass [eV]\n ' # values of the top-level parameters h3 = str(self.designMomentumEV)+','+str(self.totalCharge)+','+str(self.eMassEV)+'\n ' # label the columns h4 = 'x,xp,y,yp,s,dp\n ' # specify the units h5 = '[m],[rad],[m],[rad],[m],[rad]' # assemble the full header myHeader = h1 + h2 + h3 + h4 + h5 # write particle data into the file # create local pointer to particle array userNumberOfParticles = int(self.ui.numPtcls.text()) tmp6 = randomSampleOfBunch(self.myBunch.getDistribution6D().getPhaseSpace6D().getArray6D(), userNumberOfParticles) np.savetxt(fileName, tmp6.transpose(), fmt=str('%1.12e'), delimiter=',', comments='', header=myHeader)
def rangeUnits(textBox, array): # For some reason, max() doesn't work on numpy arrays containing non-finite numbers maxValue = float('-inf') for value in array: if isfinite(value) and value > maxValue: maxValue = value if textBox.unit != '': unit = util.displayWithUnitsNumber(maxValue, textBox.unit).split()[1] rangeInUnits = [util.convertUnitsNumber(value, textBox.unit, unit) for value in array] else: power = int(round(floor(log10(abs(maxValue)))/3)*3) # round power to nearest multiple of 3 unit = '10^' + str(power) if power != 0 else '' rangeInUnits = [x/(10**power) for x in array] axisLabel = textBox.objectName() + (' (' + unit + ')' if unit else '') return unit, axisLabel, rangeInUnits
def getValue(self, textBox): try: self.valueFromTextBox[textBox] = util.convertUnitsStringToNumber(textBox.text(), textBox.unit) return self.valueFromTextBox[textBox] except ValueError: if textBox in self.valueFromTextBox: del self.valueFromTextBox[textBox]
def saveToSDDS(self, sddsFileName = None): if not sddsFileName: sddsFileName = util.getSaveFileName(self, 'sdds') if not sddsFileName: return mySDDS = sdds.SDDS(0) mySDDS.description[0] = "RadTrack" mySDDS.description[1] = "Copyright 2013-2015 by RadiaBeam Technologies. All rights reserved." mySDDS.parameterName = ["designMomentumEV", "totalCharge", "eMassEV"] mySDDS.parameterData = [[self.designMomentumEV], [self.totalCharge], [self.eMassEV]] mySDDS.parameterDefinition = [["","","","",mySDDS.SDDS_DOUBLE,""], ["","","","",mySDDS.SDDS_DOUBLE,""], ["","","","",mySDDS.SDDS_DOUBLE,""]] mySDDS.columnName = ["x", "xp", "y", "yp", "t", "p"] tmp6 = self.myBunch.getDistribution6D().getPhaseSpace6D().getArray6D() if not self.userInputEnabled(): tmp6 = randomSampleOfBunch(tmp6, int(self.ui.numPtcls.text())) mySDDS.columnData = [ [list(tmp6[i,:])] for i in range(6)] mySDDS.columnDefinition = [["","m", "","",mySDDS.SDDS_DOUBLE,0], ["","","","",mySDDS.SDDS_DOUBLE,0], ["","m", "","",mySDDS.SDDS_DOUBLE,0], ["","","","",mySDDS.SDDS_DOUBLE,0], ["","s", "","",mySDDS.SDDS_DOUBLE,0], ["","m_ec","","",mySDDS.SDDS_DOUBLE,0]] mySDDS.save(sddsFileName)
def set_widget_value(decl, param, widget): """Sets parameter value accordingly on widget Args: decl (dict): decl for parameter param (dict): value widget (widget): what to set on Returns: str: value that was set """ t = decl.py_type if isinstance(t, enum.EnumMeta): widget.setCurrentIndex(list(t).index(param)) return rt_qt.i18n_text(param.display_name) if issubclass(t, bool): widget.setChecked(param) # Approximate size of checkbox return ' ' if decl.units: l = RbUtility.displayWithUnitsNumber(param, decl.units) else: l = str(param) widget.setText(l) return l
def importFile(self, fileName = None): """Allow importing from CSV or SDDS""" # use Qt file dialog if not fileName: fileName = QtGui.QFileDialog.getOpenFileName(self, "Import particle file", self.parent.lastUsedDirectory, util.fileTypeList(self.acceptsFileTypes)) # if user cancels out, do nothing if not fileName: return self.parent.lastUsedDirectory = os.path.dirname(fileName) if os.path.basename(fileName).startswith(self.parent.tabPrefix): if fileName.split('+')[-1].split('.')[0] == 'False': self.disableInput() else: self.disableInput() if re.search('\.csv$', fileName, re.IGNORECASE): self.readFromCSV(fileName) else: self.readFromSDDS(fileName) self.calculateTwiss() self.refreshPlots()
def _num(d, w): # need type checking if w is None: return None v = w.text() if d.units: v = RbUtility.convertUnitsStringToNumber(v, d.units) return d.py_type(v)
def exportToFile(self, fileName = None): if not fileName: fileName = util.getSaveFileName(self) if not fileName: return fileLines = [] for box in self.textBox.values(): try: try: _, unit = util.separateNumberUnit(box.text()) value = util.convertUnitsNumberToString(self.valueFromTextBox[box], box.unit, unit) except (ValueError, KeyError): value = box.text() fileLines.append(box.objectName() + ':' + value) # text box except AttributeError: fileLines.append(box.objectName() + ':' + box.currentText()) # combo box with open(fileName, 'w') as f: f.write('\n'.join(sorted(fileLines)))
def refreshPlots(self): self.parent.ui.statusbar.showMessage('Redrawing plots ...') self.erasePlots() # nothing to plot, if beam hasn't been initialized if not self.myBunch: return # get the specified units for plotting self.unitsPos = self.ui.unitsPos.text() self.unitsAngle = self.ui.unitsAngle.text() # get the number of tick marks self.numTicks = int(self.ui.numTicks.text()) # create local pointer to particle array tmp6 = randomSampleOfBunch( self.myBunch.getDistribution6D().getPhaseSpace6D().getArray6D(), min(self.maxParticles, int(self.ui.numPtcls.text()))) numParticles = tmp6.shape[1] self.calculateLimits(tmp6) nLevels = 5 + int(math.pow(numParticles, 0.33333333)) nDivs = 10 + int(math.pow(numParticles, 0.2)) # generate the four plots self.plotXY( util.convertUnitsNumber(tmp6[0,:], 'm', self.unitsPos), util.convertUnitsNumber(tmp6[2,:], 'm', self.unitsPos), nDivs, nLevels) self.plotXPX(util.convertUnitsNumber(tmp6[0,:], 'm', self.unitsPos), util.convertUnitsNumber(tmp6[1,:], 'rad', self.unitsAngle), nDivs, nLevels) self.plotYPY(util.convertUnitsNumber(tmp6[2,:], 'm', self.unitsPos), util.convertUnitsNumber(tmp6[3,:], 'rad', self.unitsAngle), nDivs, nLevels) self.plotSDP(util.convertUnitsNumber(tmp6[4,:], 'm', self.unitsPos), util.convertUnitsNumber(tmp6[5,:], 'rad', self.unitsAngle), nDivs, nLevels) self.parent.ui.statusbar.clearMessage()
def importFile(self, fileName = None): if not fileName: fileName = QtGui.QFileDialog.getOpenFileName(self, 'Open file', self.parent.lastUsedDirectory, util.fileTypeLists(self.acceptsFileTypes)) if not fileName: return self.parent.lastUsedDirectory = os.path.dirname(fileName) with open(fileName, 'r') as f: for line in f: name, value = line.strip().split(':') box = self.textBox[name] try: box.setText(value) # text box except AttributeError: box.setCurrentIndex(box.findText(value)) # combo box self.calculateAll() self.plot()
def exportToFile(self, fileName = None): if not fileName: fileName = util.getSaveFileName(self, ['sdds', 'csv']) if not fileName: return if os.path.basename(fileName).startswith(self.parent.tabPrefix): name, ext = os.path.splitext(fileName) fileName = name + '+' + str(self.userInputEnabled()) + ext with open(fileName, 'w'): pass # create file in case no data to be saved if self.userInputEnabled(): self.generateBunch() # save all particles if fileName.lower().endswith('csv'): self.saveToCSV(fileName) else: self.saveToSDDS(fileName)
def goalSeek(self): # Newton's method variableTextBox = self.textBox[self.ui.vary.currentText()] resultTextBox = self.textBox[self.ui.target.currentText()] self.ui.solverResult.setText('Searching...') maximumIterations = 1000 success = False dxFactor = 1e-9 try: x0 = self.valueFromTextBox[variableTextBox] except KeyError: x0 = dxFactor bestX = x0 try: goal = util.convertUnitsStringToNumber(self.ui.lineEdit.text(), resultTextBox.unit) y0 = self.calculateValue(variableTextBox, x0, resultTextBox) bestError = abs((y0-goal)/goal) for i in range(maximumIterations): try: y0 = self.calculateValue(variableTextBox, x0, resultTextBox) error = abs((y0-goal)/goal) if error < 1e-6: success = True break else: if error < bestError: bestX = x0 bestError = error dx = abs(dxFactor*x0) slope = self.calculateSlope(variableTextBox, x0, dx, resultTextBox) x0 = x0 - (y0-goal)/slope if x0 < 0: x0 = dx except (ZeroDivisionError, KeyError, OverflowError): dxFactor = 2*dxFactor x0 = x0+dx except ValueError: # "goal" is blank -> find extrema by Newton's method on slope dx = abs(dxFactor*x0) bestSlope = abs(self.calculateSlope(variableTextBox, x0, dx, resultTextBox)) for i in range(maximumIterations): try: dx = abs(dxFactor*x0) slope = self.calculateSlope(variableTextBox, x0, dx, resultTextBox) if abs(slope) < 1e-6: success = True break else: if slope < bestSlope: bestX = x0 bestSlope = slope secondDerivitive = self.calculateSecondDerivitive(variableTextBox, x0, dx, resultTextBox) x0 = x0 - (slope)/secondDerivitive if x0 < 0: x0 = dx except (ZeroDivisionError, KeyError, OverflowError): dxFactor = 2*dxFactor x0 = x0+dx if success: value = x0 self.ui.solverResult.setText('Success.') else: value = bestX self.ui.solverResult.setText('Failed. Could not find a solution.') variableTextBox.setText(util.displayWithUnitsNumber(util.roundSigFig(value, 5), variableTextBox.unit)) variableTextBox.setCursorPosition(0) self.calculateAll()
def plot(self): try: xTextBox = self.textBox[self.ui.x.currentText()] xOrginalValue = xTextBox.text() yTextBox = self.textBox[self.ui.y.currentText()] yOrginalValue = yTextBox.text() zTextBox = self.textBox[self.ui.z.currentText()] except KeyError: return # Combo box choice was left blank try: xmin = util.convertUnitsStringToNumber(self.ui.xmin.text(), xTextBox.unit) xmax = util.convertUnitsStringToNumber(self.ui.xmax.text(), xTextBox.unit) if xmin > xmax: xmin, xmax = xmax, xmin ymin = util.convertUnitsStringToNumber(self.ui.ymin.text(), yTextBox.unit) ymax = util.convertUnitsStringToNumber(self.ui.ymax.text(), yTextBox.unit) if ymin > ymax: ymin, ymax = ymax, ymin except ValueError: # text box left blank return numPoints = 32 # per variable, 32*32 = 1,024 points total xRange = numpy.linspace(xmin, xmax, numPoints) _, xAxisLabel, xRangeUnits = rangeUnits(xTextBox, xRange) yRange = numpy.linspace(ymin, ymax, numPoints) _, yAxisLabel, yRangeUnits = rangeUnits(yTextBox, yRange) Z = numpy.zeros((numPoints, numPoints)) plotProgress = QtGui.QProgressDialog("Plotting ...", None, 0, (numPoints**2)-1) plotProgress.setMinimumDuration(0) try: for j, x in enumerate(xRange): for i, y in enumerate(yRange): plotProgress.setValue(plotProgress.value()+1) xTextBox.setText(str(x)) yTextBox.setText(str(y)) results = calculate(self.userInputDict()) try: Z[i,j] = results[zTextBox.dictName] except KeyError: Z[i,j] = float('nan') zUnit, zAxisLabel, _ = rangeUnits(zTextBox, Z.flat) for z in numpy.nditer(Z, op_flags=['readwrite']): z[...] = util.convertUnitsNumber(z, zTextBox.unit, zUnit) # Plotting self.ui.plotWidget.canvas.fig.clear() self.ui.plotWidget.canvas.ax = self.ui.plotWidget.canvas.fig.add_subplot(111) c = self.ui.plotWidget.canvas.ax.imshow(numpy.flipud(Z), cmap = 'hot', extent = [min(xRangeUnits), max(xRangeUnits), min(yRangeUnits), max(yRangeUnits)], aspect = 'auto') self.ui.plotWidget.canvas.ax.set_xlabel(xAxisLabel) self.ui.plotWidget.canvas.ax.set_ylabel(yAxisLabel) cb = self.ui.plotWidget.canvas.fig.colorbar(c) cb.set_label(zAxisLabel) self.ui.plotWidget.canvas.ax.set_xlim(min(xRangeUnits), max(xRangeUnits)) self.ui.plotWidget.canvas.ax.set_ylim(min(yRangeUnits), max(yRangeUnits)) self.ui.plotWidget.canvas.fig.tight_layout() self.ui.plotWidget.canvas.draw() finally: # Restore text boxes to original state xTextBox.setText(xOrginalValue) xTextBox.setCursorPosition(0) yTextBox.setText(yOrginalValue) yTextBox.setCursorPosition(0) self.calculateAll()
def generateBunch(self, particleLimit = None): if self.userInputEnabled(): errorMessage = [] self.parent.ui.statusbar.showMessage('Generating bunch ...') # Get input from text boxes. try: numParticles = int(self.ui.numPtcls.text()) except ValueError: numParticles = 0 if numParticles <= 0: errorMessage.append(self.ui.numPtclsLabel.text().strip() + ' must be a postive number.') if particleLimit: numParticles = min(numParticles, particleLimit) try: self.designMomentumEV = util.convertUnitsStringToNumber(self.ui.designMomentum.text(), 'eV') except ValueError: self.designMomentumEV = 0 if self.designMomentumEV <= 0: errorMessage.append(self.ui.designMomentumLabel.text().strip() + ' must be a positive value.') try: self.totalCharge = util.convertUnitsStringToNumber(self.ui.totalCharge.text().strip(), 'C') except ValueError: self.totalCharge = 0 if self.totalCharge <= 0: errorMessage.append(self.ui.charge.text() + ' must be a positive value.') if errorMessage: QtGui.QMessageBox(QtGui.QMessageBox.Warning, 'Input Error' + ('s' if len(errorMessage) > 1 else ''), '\n'.join(errorMessage), QtGui.QMessageBox.Ok, self).exec_() self.parent.ui.statusbar.clearMessage() self.myBunch = None return beta0gamma0 = self.designMomentumEV / self.eMassEV gamma0 = math.sqrt(beta0gamma0**2 + 1.) beta0 = beta0gamma0 / gamma0 # get input from the table of Twiss parameters self.twissAlphaX = util.convertUnitsStringToNumber(self.ui.twissTable.item(0,0).text(), '') self.twissAlphaY = util.convertUnitsStringToNumber(self.ui.twissTable.item(1,0).text(), '') self.twissBetaX = util.convertUnitsStringToNumber(self.ui.twissTable.item(0,1).text(), 'm/rad') self.twissBetaY = util.convertUnitsStringToNumber(self.ui.twissTable.item(1,1).text(), 'm/rad') self.twissEmitNX = util.convertUnitsStringToNumber(self.ui.twissTable.item(0,2).text(), 'm*rad') self.twissEmitNY = util.convertUnitsStringToNumber(self.ui.twissTable.item(1,2).text(), 'm*rad') if self.longTwissFlag == "alpha-bct-dp": self.twissAlphaZ = util.convertUnitsStringToNumber(self.ui.twissTableZ.item(0,0).text(), '') self.bctRms = util.convertUnitsStringToNumber(self.ui.twissTableZ.item(0,1).text(), 'm') self.dPopRms = float(self.ui.twissTableZ.item(0,2).text()) self.twissEmitNZ = (self.bctRms/beta0) * self.dPopRms / math.sqrt(1.+self.twissAlphaZ**2) self.twissBetaZ = (self.bctRms/beta0) / self.dPopRms * math.sqrt(1.+self.twissAlphaZ**2) # elif self.longTwissFlag == "coupling-bct-dp": # msgBox = QtGui.QMessageBox() # message = 'Error --\n\n' # message += ' longTwissFlag has been specified as "'+self.longTwissFlag+'".\n' # message += ' This value is not yet supported, but is coming soon!\n\n' # message += 'Please go to the "Specification Type" button and choose "alpha-bct-dp".\n\n' # msgBox.setText(message) # msgBox.exec_() # elif self.longTwissFlag == "alpha-beta-emit": # msgBox = QtGui.QMessageBox() # message = 'Error --\n\n' # message += ' longTwissFlag has been specified as "'+self.longTwissFlag+'".\n' # message += ' This value is not yet supported, but is coming soon!\n\n' # message += 'Please go to the "Specification Type" button and choose "alpha-bct-dp".\n\n' # msgBox.setText(message) # msgBox.exec_() # else: # msgBox = QtGui.QMessageBox() # message = 'Error --\n\n' # message += ' longTwissFlag has been specified as "'+self.longTwissFlag+'".\n' # message += ' This choice is invalid!\n\n' # message += 'Please use the "Specification Type" button to choose a valid option.\n\n' # msgBox.setText(message) # msgBox.exec_() # Get input from the table of phase space offsets self.offsetX = util.convertUnitsStringToNumber(self.ui.offsetTable.item(0,0).text(), 'm') self.offsetY = util.convertUnitsStringToNumber(self.ui.offsetTable.item(1,0).text(), 'm') self.offsetT = util.convertUnitsStringToNumber(self.ui.offsetTable.item(2,0).text(), 'm') self.offsetXP = util.convertUnitsStringToNumber(self.ui.offsetTable.item(0,1).text(), 'rad') self.offsetYP = util.convertUnitsStringToNumber(self.ui.offsetTable.item(1,1).text(), 'rad') self.offsetPT = util.convertUnitsStringToNumber(self.ui.offsetTable.item(2,1).text(), 'rad') # instantiate the particle bunch self.myBunch = beam.RbParticleBeam6D(numParticles) self.myBunch.setDesignMomentumEV(self.designMomentumEV) self.myBunch.setTotalCharge(self.totalCharge) self.myBunch.setMassEV(self.eMassEV) # assume electrons # specify the distribution flag and extent self.myDist = self.myBunch.getDistribution6D() self.myDist.setDistributionType(self.distributionFlag) self.myDist.setMaxRmsFactor(3.) # specify the Twiss parameters self.myBunch.setTwissParamsByName2D(self.twissAlphaX,self.twissBetaX, self.twissEmitNX/beta0gamma0,'twissX') self.myBunch.setTwissParamsByName2D(self.twissAlphaY,self.twissBetaY, self.twissEmitNY/beta0gamma0,'twissY') self.myBunch.setTwissParamsByName2D(self.twissAlphaZ,self.twissBetaZ, self.twissEmitNZ,'twissZ') # create the distribution self.myBunch.makeParticlePhaseSpace6D() # offset the distribution if (self.offsetX != 0.): self.myDist.offsetDistribComp(self.offsetX, 0) if (self.offsetXP != 0.): self.myDist.offsetDistribComp(self.offsetXP, 1) if (self.offsetY != 0.): self.myDist.offsetDistribComp(self.offsetY, 2) if (self.offsetYP != 0.): self.myDist.offsetDistribComp(self.offsetYP, 3) if (self.offsetT != 0.): self.myDist.offsetDistribComp(self.offsetT, 4) if (self.offsetPT != 0.): self.myDist.offsetDistribComp(self.offsetPT, 5) # generate the plots self.refreshPlots() self.parent.ui.statusbar.clearMessage()
def plotGenericBefore(self, hData, vData, _canvas, nDivs, nLevels): _canvas.ax.clear() util.scatConPlot(self.plotFlag, hData, vData, _canvas.ax, nDivs, nLevels) _canvas.ax.xaxis.set_major_locator(plt.MaxNLocator(self.numTicks)) _canvas.ax.yaxis.set_major_locator(plt.MaxNLocator(self.numTicks))
def calculateLimits(self, _arr): # nothing to do, if beam hasn't been initialized if not self.myBunch: return # get average, RMS, min, max values and diffs avgArray = self.myStat.calcAverages6D(_arr) rmsArray = self.myStat.calcRmsValues6D(_arr) minArray = self.myStat.calcMinValues6D(_arr) maxArray = self.myStat.calcMaxValues6D(_arr) # calculate the differences, imposing symmetry diffZero = np.zeros(6) for iLoop in range(6): diffZero[iLoop] = max( (avgArray[iLoop]-minArray[iLoop]), (maxArray[iLoop]-avgArray[iLoop]) ) # now switch based on the specified axis flag # specify plot limits, symmetric around the zero axis if self.axisFlag == 'symmetric': self.xMax = (abs(avgArray[0])+diffZero[0])*util.convertUnitsNumber(1, 'm', self.unitsPos) self.xpMax = (abs(avgArray[1])+diffZero[1])*util.convertUnitsNumber(1, 'rad', self.unitsAngle) self.yMax = (abs(avgArray[2])+diffZero[2])*util.convertUnitsNumber(1, 'm', self.unitsPos) self.ypMax = (abs(avgArray[3])+diffZero[3])*util.convertUnitsNumber(1, 'rad', self.unitsAngle) self.ptMax = (abs(avgArray[5])+diffZero[5])*util.convertUnitsNumber(1, 'rad', self.unitsAngle) self.xMin = -self.xMax self.xpMin = -self.xpMax self.yMin = -self.yMax self.ypMin = -self.ypMax self.ptMin = -self.ptMax # specify plot limits, symmetric around the bunch (confined to 3 rms) elif self.axisFlag == 'compact': self.xMin = (avgArray[0]-3.*rmsArray[0])*util.convertUnitsNumber(1, 'm', self.unitsPos) self.xpMin = (avgArray[1]-3.*rmsArray[1])*util.convertUnitsNumber(1, 'rad', self.unitsAngle) self.yMin = (avgArray[2]-3.*rmsArray[2])*util.convertUnitsNumber(1, 'm', self.unitsPos) self.ypMin = (avgArray[3]-3.*rmsArray[3])*util.convertUnitsNumber(1, 'rad', self.unitsAngle) self.ptMin = (avgArray[5]-3.*rmsArray[5])*util.convertUnitsNumber(1, 'rad', self.unitsAngle) self.xMax = (avgArray[0]+3.*rmsArray[0])*util.convertUnitsNumber(1, 'm', self.unitsPos) self.xpMax = (avgArray[1]+3.*rmsArray[1])*util.convertUnitsNumber(1, 'rad', self.unitsAngle) self.yMax = (avgArray[2]+3.*rmsArray[2])*util.convertUnitsNumber(1, 'm', self.unitsPos) self.ypMax = (avgArray[3]+3.*rmsArray[3])*util.convertUnitsNumber(1, 'rad', self.unitsAngle) self.ptMax = (avgArray[5]+3.*rmsArray[5])*util.convertUnitsNumber(1, 'rad', self.unitsAngle) # symmetric around the bunch elif self.axisFlag == 'bunch-centered': self.xMin = (avgArray[0]-diffZero[0])*util.convertUnitsNumber(1, 'm', self.unitsPos) self.xpMin = (avgArray[1]-diffZero[1])*util.convertUnitsNumber(1, 'rad', self.unitsAngle) self.yMin = (avgArray[2]-diffZero[2])*util.convertUnitsNumber(1, 'm', self.unitsPos) self.ypMin = (avgArray[3]-diffZero[3])*util.convertUnitsNumber(1, 'rad', self.unitsAngle) self.ptMin = (avgArray[5]-diffZero[5])*util.convertUnitsNumber(1, 'rad', self.unitsAngle) self.xMax = (avgArray[0]+diffZero[0])*util.convertUnitsNumber(1, 'm', self.unitsPos) self.xpMax = (avgArray[1]+diffZero[1])*util.convertUnitsNumber(1, 'rad', self.unitsAngle) self.yMax = (avgArray[2]+diffZero[2])*util.convertUnitsNumber(1, 'm', self.unitsPos) self.ypMax = (avgArray[3]+diffZero[3])*util.convertUnitsNumber(1, 'rad', self.unitsAngle) self.ptMax = (avgArray[5]+diffZero[5])*util.convertUnitsNumber(1, 'rad', self.unitsAngle) if self.axisFlag=='compact' or self.axisFlag=='symmetric-compact': # sMin / sMax always have to be 'bunch centered' self.sMin = (avgArray[4]-3.*rmsArray[4])*util.convertUnitsNumber(1, 'm', self.unitsPos) self.sMax = (avgArray[4]+3.*rmsArray[4])*util.convertUnitsNumber(1, 'm', self.unitsPos) if self.axisFlag=='symmetric' or self.axisFlag=='bunch-centered': # sMin / sMax always have to be 'bunch centered' self.sMin = (avgArray[4]-diffZero[4])*util.convertUnitsNumber(1, 'm', self.unitsPos) self.sMax = (avgArray[4]+diffZero[4])*util.convertUnitsNumber(1, 'm', self.unitsPos)