def _setupUi(self): self.le_label = QLineEdit(self) self.sb_time = QDoubleSpinBoxPlus(self) self.sb_time.setMaximum(490) self.sb_time.setDecimals(3) self.bt_duplic = QPushButton('Duplicate', self) self.bt_duplic.setAutoDefault(False) self.bt_duplic.setDefault(False) self.bt_duplic.clicked.connect(self._emitConfigData) self.bt_cancel = QPushButton('Cancel', self) self.bt_cancel.setAutoDefault(False) self.bt_cancel.setDefault(False) self.bt_cancel.clicked.connect(self.close) # layout lay = QGridLayout() lay.setVerticalSpacing(15) lay.addWidget(QLabel('<h4>Duplicate Normalized Configuration</h4>', self), 0, 0, 1, 2, alignment=Qt.AlignCenter) lay.addWidget( QLabel( 'Choose a label and a time to insert\n' 'the new configuration:', self), 1, 0, 1, 2) lay.addWidget(QLabel('Label: ', self), 2, 0) lay.addWidget(self.le_label, 2, 1) lay.addWidget(QLabel('Time [ms]: ', self), 3, 0) lay.addWidget(self.sb_time, 3, 1) lay.addWidget(self.bt_cancel, 4, 0) lay.addWidget(self.bt_duplic, 4, 1) self.setLayout(lay)
def createEditor(self, parent, option, index): """Create editor.""" editor = QDoubleSpinBoxPlus(parent) editor.setMinimum(self.mini) editor.setMaximum(self.maxi) editor.setDecimals(self.prec) locale = QLocale(QLocale.English, country=QLocale.UnitedStates) locale.setNumberOptions(locale.RejectGroupSeparator) editor.setLocale(locale) return editor
class DuplicateNormConfig(SiriusDialog): """Auxiliary window to duplicate a normalized config.""" insertConfig = Signal(float, str, dict) def __init__(self, parent, psname2strength): """Initialize object.""" super().__init__(parent) self.setObjectName('BOApp') self.setWindowTitle('Duplicate Normalized Configuration') self.psname2strength = psname2strength self._setupUi() def _setupUi(self): self.le_label = QLineEdit(self) self.sb_time = QDoubleSpinBoxPlus(self) self.sb_time.setMaximum(490) self.sb_time.setDecimals(3) self.bt_duplic = QPushButton('Duplicate', self) self.bt_duplic.setAutoDefault(False) self.bt_duplic.setDefault(False) self.bt_duplic.clicked.connect(self._emitConfigData) self.bt_cancel = QPushButton('Cancel', self) self.bt_cancel.setAutoDefault(False) self.bt_cancel.setDefault(False) self.bt_cancel.clicked.connect(self.close) # layout lay = QGridLayout() lay.setVerticalSpacing(15) lay.addWidget(QLabel('<h4>Duplicate Normalized Configuration</h4>', self), 0, 0, 1, 2, alignment=Qt.AlignCenter) lay.addWidget( QLabel( 'Choose a label and a time to insert\n' 'the new configuration:', self), 1, 0, 1, 2) lay.addWidget(QLabel('Label: ', self), 2, 0) lay.addWidget(self.le_label, 2, 1) lay.addWidget(QLabel('Time [ms]: ', self), 3, 0) lay.addWidget(self.sb_time, 3, 1) lay.addWidget(self.bt_cancel, 4, 0) lay.addWidget(self.bt_duplic, 4, 1) self.setLayout(lay) def _emitConfigData(self): time = self.sb_time.value() label = self.le_label.text() psname2strength = self.psname2strength self.insertConfig.emit(time, label, psname2strength) self.close()
def _setupUi(self): # selection widgets self.rb_interp = QRadioButton('Interpolate') self.rb_confsrv = QRadioButton('Take value from Config Server') self.rb_create = QRadioButton('Create from template') # data widget self.config_data = QWidget() glay_data = QGridLayout(self.config_data) self.le_interp_label = QLineEdit(self) # interpolate self.le_confsrv_name = _ConfigLineEdit( parent=self, config_type='bo_normalized') # from ConfigDB self.le_confsrv_name.textChanged.connect( self._handleInsertExistingConfig) self.le_confsrv_name.setVisible(False) self.le_nominal_label = QLineEdit(self) # from template self.le_nominal_label.setVisible(False) self.sb_time = QDoubleSpinBoxPlus(self) self.sb_time.setMaximum(490) self.sb_time.setDecimals(3) self.bt_insert = QPushButton('Insert', self) self.bt_insert.setAutoDefault(False) self.bt_insert.setDefault(False) self.bt_insert.clicked.connect(self._emitConfigData) self.bt_cancel = QPushButton('Cancel', self) self.bt_cancel.setAutoDefault(False) self.bt_cancel.setDefault(False) self.bt_cancel.clicked.connect(self.close) glay_data.addWidget(QLabel('Label: ', self), 0, 0) glay_data.addWidget(self.le_interp_label, 0, 1) glay_data.addWidget(self.le_confsrv_name, 0, 1) glay_data.addWidget(self.le_nominal_label, 0, 1) glay_data.addWidget(QLabel('Time [ms]: ', self), 1, 0) glay_data.addWidget(self.sb_time, 1, 1) glay_data.addWidget(self.bt_cancel, 2, 0) glay_data.addWidget(self.bt_insert, 2, 1) # connect visibility signals self.rb_interp.toggled.connect(self.le_interp_label.setVisible) self.rb_interp.setChecked(True) self.rb_confsrv.toggled.connect(self.le_confsrv_name.setVisible) self.rb_create.toggled.connect(self.le_nominal_label.setVisible) # layout lay = QVBoxLayout() lay.addWidget(QLabel('<h4>Insert a Normalized Configuration</h4>', self), alignment=Qt.AlignCenter) lay.addWidget(self.rb_interp) lay.addWidget(self.rb_confsrv) lay.addWidget(self.rb_create) lay.addStretch() lay.addWidget(self.config_data) self.setLayout(lay)
def _setupOrbitWidget(self): self.bt_get_kicks = QPushButton('Get Kicks from SOFB', self) self.bt_get_kicks.clicked.connect(self._handleGetKicksFromSOFB) label_correctH = QLabel('Correct H', self, alignment=Qt.AlignRight | Qt.AlignVCenter) self.sb_correctH = QDoubleSpinBoxPlus(self) self.sb_correctH.setValue(self._deltas['factorH']) self.sb_correctH.setDecimals(1) self.sb_correctH.setMinimum(-10000) self.sb_correctH.setMaximum(10000) self.sb_correctH.setSingleStep(0.1) self.sb_correctH.setObjectName('factorH') self.sb_correctH.editingFinished.connect(self._handleCorrFactorsSet) labelH = QLabel('%', self) label_correctV = QLabel('Correct V', self, alignment=Qt.AlignRight | Qt.AlignVCenter) self.sb_correctV = QDoubleSpinBoxPlus(self) self.sb_correctV.setValue(self._deltas['factorV']) self.sb_correctV.setDecimals(1) self.sb_correctV.setMinimum(-10000) self.sb_correctV.setMaximum(10000) self.sb_correctV.setSingleStep(0.1) self.sb_correctV.setObjectName('factorV') self.sb_correctV.editingFinished.connect(self._handleCorrFactorsSet) labelV = QLabel('%', self) self.bt_update_ref_orbit = QPushButton('Update reference', self) self.bt_update_ref_orbit.clicked.connect( _part(self._updateReference, 'corrs')) gbox = QGroupBox('Orbit', self) lay = QGridLayout() lay.addWidget(self.bt_get_kicks, 0, 0, 1, 4) lay.addWidget(label_correctH, 1, 0) lay.addWidget(self.sb_correctH, 1, 2) lay.addWidget(labelH, 1, 3) lay.addWidget(label_correctV, 2, 0) lay.addWidget(self.sb_correctV, 2, 2) lay.addWidget(labelV, 2, 3) lay.addWidget(self.bt_update_ref_orbit, 3, 2, 1, 2) lay.setColumnStretch(0, 16) lay.setColumnStretch(1, 1) lay.setColumnStretch(2, 14) lay.setColumnStretch(3, 2) gbox.setLayout(lay) return gbox
def _setup_ui(self): self.setLayout(QVBoxLayout()) self.energy_value = QDoubleSpinBoxPlus(self) self.energy_value.setSingleStep(0.01) self.energy_value.setMinimum(self.lower_limit) self.energy_value.setMaximum(self.upper_limit) self.energy_value.setDecimals(4) if self.section == 'tb': sp_channel = 'TB-Fam:PS-B:Energy-RB' elif self.section == 'bo': sp_channel = 'BO-Fam:PS-B-1:Energy-RB' elif self.section == 'ts': sp_channel = 'TS-Fam:PS-B:Energy-RB' elif self.section == 'si': sp_channel = 'SI-Fam:PS-B1B2-1:Energy-RB' else: raise RuntimeError sp_channel = _PVName(sp_channel).substitute(prefix=_VACA_PREFIX) self.energy_sp = PyDMLabel(self) self.energy_sp.channel = sp_channel self.energy_sp.showUnits = True self._tree = PVNameTree( items=self.mags, tree_levels=('dis', 'mag_group'), parent=self) self._tree.tree.setHeaderHidden(True) self._tree.tree.setColumnCount(1) self._tree.check_all() self._tree.collapse_all() self.set_energy = QPushButton('Set', self) self.set_energy.clicked.connect(self._process) # forml = Q hbl = QHBoxLayout() # hbl.addStretch() hbl.addWidget(QLabel('<h4>New Energy:</h4> ', self)) hbl.addWidget(self.energy_value) self.layout().addLayout(hbl) hbl = QHBoxLayout() # hbl.addStretch() hbl.addWidget(QLabel('Current Energy: ', self)) hbl.addWidget(self.energy_sp) self.layout().addLayout(hbl) self.layout().addWidget(self._tree) self.layout().addWidget(self.set_energy)
def _setupStrengthWidget(self): scrollarea = QScrollArea() self.nconfig_data = QWidget() flay_configdata = QFormLayout() psnames = self._get_PSNames() self._map_psnames2wigdets = dict() for ps in psnames: ps = SiriusPVName(ps) if ps in ramp.BoosterRamp.PSNAME_DIPOLES: ps_value = QLabel(str(self.norm_config[ps])+' GeV', self) flay_configdata.addRow(QLabel(ps + ': ', self), ps_value) else: ps_value = QDoubleSpinBoxPlus(self.nconfig_data) ps_value.setDecimals(6) ps_value.setMinimum(-10000) ps_value.setMaximum(10000) ps_value.setValue(self.norm_config[ps]) ps_value.valueChanged.connect(self._handleStrenghtsSet) if ps.dev in {'QD', 'QF', 'QS'}: unit_txt = '1/m' elif ps.dev in {'SD', 'SF'}: unit_txt = '1/m²' else: unit_txt = 'urad' label_unit = QLabel(unit_txt, self) label_unit.setStyleSheet("min-width:2.5em; max-width:2.5em;") hb = QHBoxLayout() hb.addWidget(ps_value) hb.addWidget(label_unit) flay_configdata.addRow(QLabel(ps + ': ', self), hb) ps_value.setObjectName(ps) ps_value.setStyleSheet("min-height:1.29em; max-height:1.29em;") self._map_psnames2wigdets[ps] = ps_value self.nconfig_data.setObjectName('data') self.nconfig_data.setStyleSheet(""" #data{background-color: transparent;}""") self.nconfig_data.setLayout(flay_configdata) scrollarea.setWidget(self.nconfig_data) self.cb_checklims = QCheckBox('Set limits according to energy', self) self.cb_checklims.setChecked(False) self.cb_checklims.stateChanged.connect(self._handleStrengtsLimits) self.bt_graph = QPushButton(qta.icon('mdi.chart-line'), '', self) self.bt_graph.clicked.connect(self._show_kicks_graph) gbox = QGroupBox() gbox.setObjectName('strengths') gbox.setStyleSheet('#strengths{min-width:20em;}') glay = QGridLayout() glay.addWidget(scrollarea, 0, 0, 1, 2) glay.addWidget(self.cb_checklims, 1, 0, alignment=Qt.AlignLeft) glay.addWidget(self.bt_graph, 1, 1, alignment=Qt.AlignRight) gbox.setLayout(glay) return gbox
def _setupChromWidget(self): for cord in ['X', 'Y']: setattr(self, 'label_Chrom'+cord, QLabel('ξ<sub>'+cord+'</sub>: ')) lab = getattr(self, 'label_Chrom'+cord) lab.setStyleSheet("min-width:1.55em; max-width:1.55em;") setattr(self, 'sb_Chrom'+cord, QDoubleSpinBoxPlus(self)) sb = getattr(self, 'sb_Chrom'+cord) sb.setDecimals(6) sb.setMinimum(-5) sb.setMaximum(5) sb.setSingleStep(0.0001) sb.setObjectName('chrom'+cord) sb.setValue(self._deltas['chrom'+cord]) sb.editingFinished.connect(self._handleChromSet) label_SL = QLabel('<h4>ΔSL [1/m<sup>2</sup>]</h4>', self) label_SL.setStyleSheet("""min-height:1.55em; max-height:1.55em; qproperty-alignment: AlignCenter;""") self.l_deltaSLSF = QLabel('', self) self.l_deltaSLSD = QLabel('', self) self.bt_update_ref_deltaSL = QPushButton('Update reference', self) self.bt_update_ref_deltaSL.clicked.connect( _part(self._updateReference, 'sexts')) gbox = QGroupBox('Chromaticity', self) lay = QGridLayout() lay.addWidget(self.label_ChromX, 1, 0) lay.addWidget(self.sb_ChromX, 1, 1) lay.addWidget(self.label_ChromY, 1, 3) lay.addWidget(self.sb_ChromY, 1, 4) lay.addWidget(label_SL, 3, 0, 1, 5) lay.addWidget(QLabel('SF: '), 4, 0) lay.addWidget(self.l_deltaSLSF, 4, 1) lay.addWidget(QLabel('SD: '), 4, 3) lay.addWidget(self.l_deltaSLSD, 4, 4) lay.addWidget(self.bt_update_ref_deltaSL, 6, 3, 1, 2) lay.setVerticalSpacing(6) lay.setColumnStretch(0, 2) lay.setColumnStretch(1, 4) lay.setColumnStretch(2, 1) lay.setColumnStretch(3, 2) lay.setColumnStretch(4, 4) lay.setRowStretch(0, 1) lay.setRowStretch(1, 2) lay.setRowStretch(2, 1) lay.setRowStretch(3, 2) lay.setRowStretch(4, 2) lay.setRowStretch(5, 1) lay.setRowStretch(6, 2) gbox.setLayout(lay) return gbox
def setupui(self): self.setLayout(QVBoxLayout()) self.layout().addWidget(QLabel('<h2>' + self.name + '</h2>'), alignment=Qt.AlignCenter) self.graph = Graph(self) self.graph.setShowLegend(self._legend) self.graph.maxRedrawRate = 1 / 2 self.layout().addWidget(self.graph) for i, pvn in enumerate(self._pvslist): frac = int(i / (len(self._pvslist) - 1) * 255) color = QColor(frac, 0, 255 - frac) opts = dict(y_channel='A', name=pvn, color=color, redraw_mode=2, lineStyle=1, lineWidth=1, symbol=None, symbolSize=None) self.graph.addChannel(**opts) self.curves.append(self.graph.curveAtIndex(i)) spinini = QSpinBoxPlus(self) spinini.setMinimum(0) spinini.setMaximum(4000) spinini.setValue(self._idx_ini) spinini.editingFinished.connect(self._update_idx_ini) spindlt = QDoubleSpinBoxPlus(self) spindlt.setMinimum(0) spindlt.setMaximum(4) spindlt.setValue(self._delta) spindlt.editingFinished.connect(self._update_delta) spinfin = QSpinBoxPlus(self) spinfin.setMinimum(0) spinfin.setMaximum(4000) spinfin.setValue(self._idx_fin) spinfin.editingFinished.connect(self._update_idx_fin) hl = QHBoxLayout() hl.addWidget(QLabel('Spacing:', self)) hl.addWidget(spindlt) hl.addStretch() hl.addWidget(QLabel('Initial Index:', self)) hl.addWidget(spinini) hl.addStretch() hl.addWidget(QLabel('Final Index:', self)) hl.addWidget(spinfin) hl.addStretch() self.layout().addLayout(hl)
def _setupTuneWidget(self): for cord in ['X', 'Y']: setattr(self, 'label_deltaTune'+cord, QLabel('Δν<sub>'+cord+'</sub>: ')) lab = getattr(self, 'label_deltaTune'+cord) lab.setStyleSheet("min-width:1.55em; max-width:1.55em;") setattr(self, 'sb_deltaTune'+cord, QDoubleSpinBoxPlus(self)) sb = getattr(self, 'sb_deltaTune'+cord) sb.setDecimals(6) sb.setMinimum(-5) sb.setMaximum(5) sb.setSingleStep(0.0001) sb.setObjectName('tune'+cord) sb.editingFinished.connect(self._handleDeltaTuneSet) label_KL = QLabel('<h4>ΔKL [1/m]</h4>', self) label_KL.setStyleSheet("""min-height:1.55em; max-height:1.55em; qproperty-alignment: AlignCenter;""") self.l_deltaKLQF = QLabel('', self) self.l_deltaKLQD = QLabel('', self) self.bt_update_ref_deltaKL = QPushButton('Update reference', self) self.bt_update_ref_deltaKL.clicked.connect( _part(self._updateReference, 'quads')) gbox = QGroupBox('Tune', self) lay = QGridLayout() lay.addWidget(self.label_deltaTuneX, 1, 0) lay.addWidget(self.sb_deltaTuneX, 1, 1) lay.addWidget(self.label_deltaTuneY, 1, 3) lay.addWidget(self.sb_deltaTuneY, 1, 4) lay.addWidget(label_KL, 3, 0, 1, 5) lay.addWidget(QLabel('QF: '), 4, 0) lay.addWidget(self.l_deltaKLQF, 4, 1) lay.addWidget(QLabel('QD: '), 4, 3) lay.addWidget(self.l_deltaKLQD, 4, 4) lay.addWidget(self.bt_update_ref_deltaKL, 6, 3, 1, 2) lay.setVerticalSpacing(6) lay.setColumnStretch(0, 2) lay.setColumnStretch(1, 4) lay.setColumnStretch(2, 1) lay.setColumnStretch(3, 2) lay.setColumnStretch(4, 4) lay.setRowStretch(0, 1) lay.setRowStretch(1, 2) lay.setRowStretch(2, 1) lay.setRowStretch(3, 2) lay.setRowStretch(4, 2) lay.setRowStretch(5, 1) lay.setRowStretch(6, 2) gbox.setLayout(lay) return gbox
def _open_matrix_sel(self): wid = QDialog(self) wid.setObjectName(self._csorb.acc + 'App') wid.setLayout(QVBoxLayout()) cbbox = QComboBox(wid) cbbox.setEditable(True) cbbox.setMaxVisibleItems(10) corrnames = self._csorb.ch_names + self._csorb.cv_names if self._csorb.acc in {'SI', 'BO'}: corrnames.append('RF') cbbox.addItems(corrnames) wid.layout().addWidget(QLabel('Choose the corrector:', wid)) wid.layout().addWidget(cbbox) ledit = QDoubleSpinBoxPlus(wid) ledit.setMinimum(float('-inf')) ledit.setMaximum(float('inf')) ledit.setValue(1.0) wid.layout().addWidget(QLabel('Choose the Kick [urad]:', wid)) wid.layout().addWidget(ledit) ledit.valueChanged.connect(_part(self._accept_mat_sel, ledit, cbbox)) cbbox.currentIndexChanged.connect( _part(self._accept_mat_sel, ledit, cbbox)) hlay = QHBoxLayout() cancel = QPushButton('Cancel', wid) confirm = QPushButton('Ok', wid) cancel.clicked.connect(wid.reject) confirm.clicked.connect(wid.accept) confirm.clicked.connect(_part(self._accept_mat_sel, ledit, cbbox)) confirm.setDefault(True) hlay.addStretch() hlay.addWidget(cancel) hlay.addStretch() hlay.addWidget(confirm) hlay.addStretch() wid.layout().addItem(hlay) res = wid.exec_() if res != QDialog.Accepted: self._reset_orbit()
def _setupUi(self): # Layout to enter matype_label = QLabel('Choose a magnet: ', self) self._matype_cb = QComboBox(self) self._matype_items = MASearch.get_pwrsupply_manames() self._matype_cb.addItem('Select...') self._matype_cb.addItems(self._matype_items) self._matype_cb.setEditable(True) self._matype_cb.setMaxVisibleItems(10) self._matype_cb.currentIndexChanged.connect( self._fill_normalizer_layout) hlmatype = QHBoxLayout() hlmatype.setAlignment(Qt.AlignLeft) hlmatype.addWidget(matype_label) hlmatype.addWidget(self._matype_cb) # Layout to enter normalizer data self._lb_current = QLabel('Current [A]: ') lb_arrow = QLabel('↔', self, alignment=Qt.AlignCenter) lb_arrow.setStyleSheet('min-width:1.2em; max-width:1.2em;') self._lb_strength = QLabel('Strength: ') self._lb_energy = QLabel('Dipole Energy [GeV]: ') self._lb_energy.setVisible(False) self._lb_quadfam_kl = QLabel('Family KL [1/m]: ') self._lb_quadfam_kl.setVisible(False) for name in ['_sb_current', '_sb_strength', '_sb_energy', '_sb_quadfam_kl']: setattr(self, name, QDoubleSpinBoxPlus()) sb = getattr(self, name) sb.setObjectName(name) sb.setValue(0) sb.setMinimum(-100000) sb.setMaximum(100000) sb.setDecimals(4) sb.setStyleSheet("min-width:8em; max-width:8em;") sb.editingFinished.connect(self._update_inputs) if name in ['_sb_current', '_sb_strength']: sb.setEnabled(False) else: sb.setVisible(False) norm_lay = QGridLayout() norm_lay.setAlignment(Qt.AlignLeft) norm_lay.setHorizontalSpacing(5) norm_lay.addItem( QSpacerItem(15, 1, QSzPlcy.Fixed, QSzPlcy.Ignored), 1, 0) norm_lay.addWidget(self._lb_current, 0, 1) norm_lay.addWidget(self._sb_current, 1, 1) norm_lay.addWidget(lb_arrow, 0, 2, 2, 1) norm_lay.addWidget(self._lb_strength, 0, 3) norm_lay.addWidget(self._sb_strength, 1, 3) norm_lay.addItem( QSpacerItem(15, 1, QSzPlcy.Fixed, QSzPlcy.Ignored), 1, 4) norm_lay.addWidget(self._lb_energy, 0, 5) norm_lay.addWidget(self._sb_energy, 1, 5) norm_lay.addItem( QSpacerItem(15, 1, QSzPlcy.Fixed, QSzPlcy.Ignored), 1, 6) norm_lay.addWidget(self._lb_quadfam_kl, 0, 7) norm_lay.addWidget(self._sb_quadfam_kl, 1, 7) self.norm_gb = QGroupBox('', self) self.norm_gb.setLayout(norm_lay) # General layout layout = QVBoxLayout() layout.setSpacing(20) layout.addWidget( QLabel('<h2>Offline Strength/Current Converter</h2>', self, alignment=Qt.AlignCenter)) layout.addLayout(hlmatype) layout.addWidget(self.norm_gb) cw = QWidget(self) cw.setObjectName('central_widget') cw.setStyleSheet("""#central_widget{min-width:42em;}""") cw.setLayout(layout) self.setCentralWidget(cw) self.setFocusPolicy(Qt.StrongFocus)
def _setupUi(self): cw = QWidget(self) self.setCentralWidget(cw) self.setFocusPolicy(Qt.StrongFocus) label = QLabel('<h4>Booster Charge</h4>', self, alignment=Qt.AlignCenter) # timeplot self.timeplot = SiriusTimePlot(parent=self, background='w') timespan = 60 * 60 * 6 colors = ['blue', 'red', 'green', 'magenta'] self.timeplot.timeSpan = timespan # [s] self.timeplot.bufferSize = 2 * timespan # [2 samples/s] self.timeplot.autoRangeY = True self.timeplot.showXGrid = True self.timeplot.showYGrid = True self.timeplot.setLabel('left', text='Charge', units='nC') self.timeplot.setObjectName('timeplot') self.timeplot.setStyleSheet( '#timeplot{min-width:28em; min-height: 18em;}') t_end = Time.now() t_init = t_end - timespan self._channels = dict() self._curves = dict() self._cb_show = dict() self._pvs_labels = dict() self._cb_offsets = dict() glay_aux = QGridLayout() glay_aux.setHorizontalSpacing(20) glay_aux.setVerticalSpacing(10) glay_aux.addWidget(QLabel('Show curves: ', self), 0, 0, alignment=Qt.AlignCenter) glay_aux.addWidget(QLabel('Offset [nC]: ', self), 2, 0, alignment=Qt.AlignCenter) for i, e in enumerate(self._energies): pvname = self._ioc_prefix.substitute(propty='Charge' + e + '-Mon') self._channels[e] = SiriusConnectionSignal(address=pvname) self._channels[e].new_value_signal[float].connect( self._update_charges) self.timeplot.addYChannel('Charge' + e, color=colors[i], lineWidth=2) curve = self.timeplot.curveAtIndex(-1) self._curves[e] = curve self.timeplot.fill_curve_with_archdata(self._curves[e], pvname, t_init=t_init.get_iso8601(), t_end=t_end.get_iso8601()) cb = QCheckBox(e) cb.setChecked(True) cb.setStyleSheet('color:' + colors[i] + ';') cb.stateChanged.connect(curve.setVisible) self._cb_show[e] = cb lb = QLabel('', self, alignment=Qt.AlignCenter) self._pvs_labels[e] = lb sb = QDoubleSpinBoxPlus(self) sb.energy = e sb.setMinimum(0) sb.setMaximum(1e6) sb.setDecimals(4) sb.setStyleSheet('max-width: 5em;') sb.setValue(self._latest_offsets[e]) sb.editingFinished.connect(self._update_offset) self._cb_offsets[e] = sb glay_aux.addWidget(cb, 0, i + 1, alignment=Qt.AlignCenter) glay_aux.addWidget(lb, 1, i + 1, alignment=Qt.AlignCenter) glay_aux.addWidget(sb, 2, i + 1, alignment=Qt.AlignCenter) self.pb_offset = QPushButton('Update offset', self) self.pb_offset.clicked.connect(self._set_current_values_2_offset) self.pb_offset.setToolTip('Set offsets to current charge values.') glay_aux.addWidget(self.pb_offset, 1, 0) lay = QVBoxLayout(cw) lay.addWidget(label) lay.addWidget(self.timeplot) lay.addLayout(glay_aux)
class BONormEdit(SiriusMainWindow): """Widget to perform optics adjust in normalized configurations.""" normConfigChanged = Signal(float, dict) def __init__(self, parent=None, prefix='', ramp_config=None, norm_config=None, time=None, energy=None, magnets=dict(), conn_sofb=None, tunecorr_configname=None, chromcorr_configname=None): """Initialize object.""" super().__init__(parent) self.setWindowTitle('Edit Normalized Configuration') self.setObjectName('BOApp') self.prefix = prefix self.ramp_config = ramp_config self.norm_config = _dcopy(norm_config) self.time = time self.energy = energy self._aux_magnets = magnets self._conn_sofb = conn_sofb self._tunecorr = BOTuneCorr(tunecorr_configname) self._chromcorr = BOChromCorr(chromcorr_configname) self._reference = _dcopy(norm_config) self._currChrom = self._estimateChrom(use_ref=True) self._deltas = { 'kicks': dict(), 'factorH': 0.0, 'factorV': 0.0, 'tuneX': 0.0, 'tuneY': 0.0, 'chromX': self._currChrom[0], 'chromY': self._currChrom[1], } self._setupUi() self._setupMenu() self.verifySync() # ---------- setup/build layout ---------- def _setupUi(self): self.label_description = QLabel( '<h2>'+self.norm_config['label']+'</h2>', self) self.label_description.setAlignment(Qt.AlignCenter) self.label_time = QLabel('<h2>T = '+str(self.time)+'ms</h2>', self) self.label_time.setAlignment(Qt.AlignCenter) self.strengths = self._setupStrengthWidget() self.orbit = self._setupOrbitWidget() self.tune = self._setupTuneWidget() self.chrom = self._setupChromWidget() self.bt_apply = QPushButton(qta.icon('fa5s.angle-right'), '', self) self.bt_apply.setToolTip('Apply Changes to Machine') self.bt_apply.setStyleSheet('icon-size: 30px 30px;') self.bt_apply.clicked.connect(self._updateRampConfig) cw = QWidget() lay = QGridLayout() lay.setVerticalSpacing(10) lay.setHorizontalSpacing(10) lay.addWidget(self.label_description, 0, 0, 1, 2) lay.addWidget(self.label_time, 1, 0, 1, 2) lay.addWidget(self.strengths, 2, 0, 4, 1) lay.addWidget(self.orbit, 2, 1) lay.addWidget(self.tune, 3, 1) lay.addWidget(self.chrom, 4, 1) lay.addWidget(self.bt_apply, 5, 1) lay.setColumnStretch(0, 2) lay.setColumnStretch(1, 2) lay.setRowStretch(0, 2) lay.setRowStretch(1, 2) lay.setRowStretch(2, 8) lay.setRowStretch(3, 8) lay.setRowStretch(4, 8) lay.setRowStretch(5, 1) cw.setLayout(lay) cw.setStyleSheet(""" QGroupBox::title{ subcontrol-origin: margin; subcontrol-position: top center; padding: 0 2px 0 2px;}""") cw.setFocusPolicy(Qt.StrongFocus) self.setCentralWidget(cw) def _setupMenu(self): self.menubar = QMenuBar(self) self.layout().setMenuBar(self.menubar) self.menu = self.menubar.addMenu('Options') self.act_saveas = self.menu.addAction('Save as...') self.act_saveas.triggered.connect(self._showSaveAsPopup) self._undo_stack = QUndoStack(self) self.act_undo = self._undo_stack.createUndoAction(self, 'Undo') self.act_undo.setShortcut(QKeySequence.Undo) self.menu.addAction(self.act_undo) self.act_redo = self._undo_stack.createRedoAction(self, 'Redo') self.act_redo.setShortcut(QKeySequence.Redo) self.menu.addAction(self.act_redo) def _setupStrengthWidget(self): scrollarea = QScrollArea() self.nconfig_data = QWidget() flay_configdata = QFormLayout() psnames = self._get_PSNames() self._map_psnames2wigdets = dict() for ps in psnames: ps = SiriusPVName(ps) if ps in ramp.BoosterRamp.PSNAME_DIPOLES: ps_value = QLabel(str(self.norm_config[ps])+' GeV', self) flay_configdata.addRow(QLabel(ps + ': ', self), ps_value) else: ps_value = QDoubleSpinBoxPlus(self.nconfig_data) ps_value.setDecimals(6) ps_value.setMinimum(-10000) ps_value.setMaximum(10000) ps_value.setValue(self.norm_config[ps]) ps_value.valueChanged.connect(self._handleStrenghtsSet) if ps.dev in {'QD', 'QF', 'QS'}: unit_txt = '1/m' elif ps.dev in {'SD', 'SF'}: unit_txt = '1/m²' else: unit_txt = 'urad' label_unit = QLabel(unit_txt, self) label_unit.setStyleSheet("min-width:2.5em; max-width:2.5em;") hb = QHBoxLayout() hb.addWidget(ps_value) hb.addWidget(label_unit) flay_configdata.addRow(QLabel(ps + ': ', self), hb) ps_value.setObjectName(ps) ps_value.setStyleSheet("min-height:1.29em; max-height:1.29em;") self._map_psnames2wigdets[ps] = ps_value self.nconfig_data.setObjectName('data') self.nconfig_data.setStyleSheet(""" #data{background-color: transparent;}""") self.nconfig_data.setLayout(flay_configdata) scrollarea.setWidget(self.nconfig_data) self.cb_checklims = QCheckBox('Set limits according to energy', self) self.cb_checklims.setChecked(False) self.cb_checklims.stateChanged.connect(self._handleStrengtsLimits) self.bt_graph = QPushButton(qta.icon('mdi.chart-line'), '', self) self.bt_graph.clicked.connect(self._show_kicks_graph) gbox = QGroupBox() gbox.setObjectName('strengths') gbox.setStyleSheet('#strengths{min-width:20em;}') glay = QGridLayout() glay.addWidget(scrollarea, 0, 0, 1, 2) glay.addWidget(self.cb_checklims, 1, 0, alignment=Qt.AlignLeft) glay.addWidget(self.bt_graph, 1, 1, alignment=Qt.AlignRight) gbox.setLayout(glay) return gbox def _setupOrbitWidget(self): self.bt_get_kicks = QPushButton('Get Kicks from SOFB', self) self.bt_get_kicks.clicked.connect(self._handleGetKicksFromSOFB) label_correctH = QLabel('Correct H', self, alignment=Qt.AlignRight | Qt.AlignVCenter) self.sb_correctH = QDoubleSpinBoxPlus(self) self.sb_correctH.setValue(self._deltas['factorH']) self.sb_correctH.setDecimals(1) self.sb_correctH.setMinimum(-10000) self.sb_correctH.setMaximum(10000) self.sb_correctH.setSingleStep(0.1) self.sb_correctH.setObjectName('factorH') self.sb_correctH.editingFinished.connect(self._handleCorrFactorsSet) labelH = QLabel('%', self) label_correctV = QLabel('Correct V', self, alignment=Qt.AlignRight | Qt.AlignVCenter) self.sb_correctV = QDoubleSpinBoxPlus(self) self.sb_correctV.setValue(self._deltas['factorV']) self.sb_correctV.setDecimals(1) self.sb_correctV.setMinimum(-10000) self.sb_correctV.setMaximum(10000) self.sb_correctV.setSingleStep(0.1) self.sb_correctV.setObjectName('factorV') self.sb_correctV.editingFinished.connect(self._handleCorrFactorsSet) labelV = QLabel('%', self) self.bt_update_ref_orbit = QPushButton('Update reference', self) self.bt_update_ref_orbit.clicked.connect( _part(self._updateReference, 'corrs')) gbox = QGroupBox('Orbit', self) lay = QGridLayout() lay.addWidget(self.bt_get_kicks, 0, 0, 1, 4) lay.addWidget(label_correctH, 1, 0) lay.addWidget(self.sb_correctH, 1, 2) lay.addWidget(labelH, 1, 3) lay.addWidget(label_correctV, 2, 0) lay.addWidget(self.sb_correctV, 2, 2) lay.addWidget(labelV, 2, 3) lay.addWidget(self.bt_update_ref_orbit, 3, 2, 1, 2) lay.setColumnStretch(0, 16) lay.setColumnStretch(1, 1) lay.setColumnStretch(2, 14) lay.setColumnStretch(3, 2) gbox.setLayout(lay) return gbox def _setupTuneWidget(self): for cord in ['X', 'Y']: setattr(self, 'label_deltaTune'+cord, QLabel('Δν<sub>'+cord+'</sub>: ')) lab = getattr(self, 'label_deltaTune'+cord) lab.setStyleSheet("min-width:1.55em; max-width:1.55em;") setattr(self, 'sb_deltaTune'+cord, QDoubleSpinBoxPlus(self)) sb = getattr(self, 'sb_deltaTune'+cord) sb.setDecimals(6) sb.setMinimum(-5) sb.setMaximum(5) sb.setSingleStep(0.0001) sb.setObjectName('tune'+cord) sb.editingFinished.connect(self._handleDeltaTuneSet) label_KL = QLabel('<h4>ΔKL [1/m]</h4>', self) label_KL.setStyleSheet("""min-height:1.55em; max-height:1.55em; qproperty-alignment: AlignCenter;""") self.l_deltaKLQF = QLabel('', self) self.l_deltaKLQD = QLabel('', self) self.bt_update_ref_deltaKL = QPushButton('Update reference', self) self.bt_update_ref_deltaKL.clicked.connect( _part(self._updateReference, 'quads')) gbox = QGroupBox('Tune', self) lay = QGridLayout() lay.addWidget(self.label_deltaTuneX, 1, 0) lay.addWidget(self.sb_deltaTuneX, 1, 1) lay.addWidget(self.label_deltaTuneY, 1, 3) lay.addWidget(self.sb_deltaTuneY, 1, 4) lay.addWidget(label_KL, 3, 0, 1, 5) lay.addWidget(QLabel('QF: '), 4, 0) lay.addWidget(self.l_deltaKLQF, 4, 1) lay.addWidget(QLabel('QD: '), 4, 3) lay.addWidget(self.l_deltaKLQD, 4, 4) lay.addWidget(self.bt_update_ref_deltaKL, 6, 3, 1, 2) lay.setVerticalSpacing(6) lay.setColumnStretch(0, 2) lay.setColumnStretch(1, 4) lay.setColumnStretch(2, 1) lay.setColumnStretch(3, 2) lay.setColumnStretch(4, 4) lay.setRowStretch(0, 1) lay.setRowStretch(1, 2) lay.setRowStretch(2, 1) lay.setRowStretch(3, 2) lay.setRowStretch(4, 2) lay.setRowStretch(5, 1) lay.setRowStretch(6, 2) gbox.setLayout(lay) return gbox def _setupChromWidget(self): for cord in ['X', 'Y']: setattr(self, 'label_Chrom'+cord, QLabel('ξ<sub>'+cord+'</sub>: ')) lab = getattr(self, 'label_Chrom'+cord) lab.setStyleSheet("min-width:1.55em; max-width:1.55em;") setattr(self, 'sb_Chrom'+cord, QDoubleSpinBoxPlus(self)) sb = getattr(self, 'sb_Chrom'+cord) sb.setDecimals(6) sb.setMinimum(-5) sb.setMaximum(5) sb.setSingleStep(0.0001) sb.setObjectName('chrom'+cord) sb.setValue(self._deltas['chrom'+cord]) sb.editingFinished.connect(self._handleChromSet) label_SL = QLabel('<h4>ΔSL [1/m<sup>2</sup>]</h4>', self) label_SL.setStyleSheet("""min-height:1.55em; max-height:1.55em; qproperty-alignment: AlignCenter;""") self.l_deltaSLSF = QLabel('', self) self.l_deltaSLSD = QLabel('', self) self.bt_update_ref_deltaSL = QPushButton('Update reference', self) self.bt_update_ref_deltaSL.clicked.connect( _part(self._updateReference, 'sexts')) gbox = QGroupBox('Chromaticity', self) lay = QGridLayout() lay.addWidget(self.label_ChromX, 1, 0) lay.addWidget(self.sb_ChromX, 1, 1) lay.addWidget(self.label_ChromY, 1, 3) lay.addWidget(self.sb_ChromY, 1, 4) lay.addWidget(label_SL, 3, 0, 1, 5) lay.addWidget(QLabel('SF: '), 4, 0) lay.addWidget(self.l_deltaSLSF, 4, 1) lay.addWidget(QLabel('SD: '), 4, 3) lay.addWidget(self.l_deltaSLSD, 4, 4) lay.addWidget(self.bt_update_ref_deltaSL, 6, 3, 1, 2) lay.setVerticalSpacing(6) lay.setColumnStretch(0, 2) lay.setColumnStretch(1, 4) lay.setColumnStretch(2, 1) lay.setColumnStretch(3, 2) lay.setColumnStretch(4, 4) lay.setRowStretch(0, 1) lay.setRowStretch(1, 2) lay.setRowStretch(2, 1) lay.setRowStretch(3, 2) lay.setRowStretch(4, 2) lay.setRowStretch(5, 1) lay.setRowStretch(6, 2) gbox.setLayout(lay) return gbox # ---------- server communication ---------- def _save(self, name): try: nconf = ramp.BoosterNormalized() nconf.value = self.norm_config nconf.save(new_name=name) except _ConfigDBException as err: QMessageBox.critical(self, 'Error', str(err), QMessageBox.Ok) def _showSaveAsPopup(self): self._saveAsPopup = _SaveConfigDialog('bo_normalized', self) self._saveAsPopup.configname.connect(self._save) self._saveAsPopup.open() def verifySync(self): if self.ramp_config is None: return if not self.ramp_config.verify_ps_normalized_synchronized( self.time, value=self.norm_config): self.label_time.setStyleSheet('color: red;') self.label_description.setStyleSheet('color: red;') self.setToolTip("There are unsaved changes") else: self.label_time.setStyleSheet('color: black;') self.label_description.setStyleSheet('color: black;') self.setToolTip("") # ---------- strengths ---------- def _handleStrenghtsSet(self, new_value): psname = self.sender().objectName() self._stack_command( self.sender(), self.norm_config[psname], new_value, message='set '+psname+' strength to {}'.format(new_value)) self.norm_config[psname] = new_value self.verifySync() def _handleStrengtsLimits(self, state): psnames = list(self.norm_config.keys()) psnames.remove('BO-Fam:PS-B-1') psnames.remove('BO-Fam:PS-B-2') psnames.remove('label') if state: for ps in psnames: ps_value = self.nconfig_data.findChild( QDoubleSpinBoxPlus, name=ps) ma = _MASearch.conv_psname_2_psmaname(ps) aux = self._aux_magnets[ma] currs = (aux.current_min, aux.current_max) lims = aux.conv_current_2_strength( currents=currs, strengths_dipole=self.energy) ps_value.setMinimum(min(lims)) ps_value.setMaximum(max(lims)) else: for ps in psnames: ps_value = self.nconfig_data.findChild( QDoubleSpinBoxPlus, name=ps) ps_value.setMinimum(-10000) ps_value.setMaximum(10000) def _updateStrenghtsWidget(self, pstype): psnames = self._get_PSNames(pstype) wid2change = psnames if psnames else list(self.norm_config.keys()) for wid in wid2change: value = self.norm_config[wid] self._map_psnames2wigdets[wid].setValue(value) # ---------- orbit ---------- def _updateCorrKicks(self): for psname, dkick in self._deltas['kicks'].items(): corr_factor = self._deltas['factorV'] if 'CV' in psname \ else self._deltas['factorH'] corr_factor /= 100 self.norm_config[psname] = self._reference[psname] + \ dkick*corr_factor def _handleGetKicksFromSOFB(self): if not self._conn_sofb.connected: QMessageBox.warning( self, 'Not Connected', 'There are not connected PVs!', QMessageBox.Ok) return dkicks = self._conn_sofb.get_deltakicks() if not dkicks: QMessageBox.warning( self, 'Could not get kicks', 'Could not get kicks from SOFB!', QMessageBox.Ok) return self._deltas['kicks'] = dkicks self._updateCorrKicks() self._updateStrenghtsWidget('corrs') self.verifySync() def _handleCorrFactorsSet(self): widget = self.sender() factor = widget.objectName() dim = ' vertical ' if factor == 'factorV' else ' horizantal ' new_value = widget.value() self._stack_command( widget, self._deltas[factor], new_value, message='set'+dim+'orbit correction factor to {}'.format( new_value)) self._deltas[factor] = new_value self._updateCorrKicks() self._updateStrenghtsWidget('corrs') self.verifySync() def _resetOrbitChanges(self): self._deltas['kicks'] = dict() self._deltas['factorH'] = 0.0 self._deltas['factorV'] = 0.0 self.sb_correctH.setValue(0.0) self.sb_correctV.setValue(0.0) # ---------- tune ---------- def _handleDeltaTuneSet(self): widget = self.sender() tune = widget.objectName() dim = ' vertical ' if tune == 'tuneY' else ' horizantal ' new_value = widget.value() self._stack_command( widget, self._deltas[tune], new_value, message='set'+dim+'delta tune to {}'.format( new_value)) self._deltas[tune] = new_value self._updateDeltaKL() def _updateDeltaKL(self): self._deltaKL = self._tunecorr.calculate_deltaKL( [self._deltas['tuneX'], self._deltas['tuneY']]) self.l_deltaKLQF.setText('{: 4f}'.format(self._deltaKL[0])) self.l_deltaKLQD.setText('{: 4f}'.format(self._deltaKL[1])) self.norm_config['BO-Fam:PS-QF'] = \ self._reference['BO-Fam:PS-QF'] + self._deltaKL[0] self.norm_config['BO-Fam:PS-QD'] = \ self._reference['BO-Fam:PS-QD'] + self._deltaKL[1] self._updateStrenghtsWidget('quads') self.verifySync() def _resetTuneChanges(self): self.sb_deltaTuneX.setValue(0) self.sb_deltaTuneY.setValue(0) self._deltaKL = [0.0, 0.0] self.l_deltaKLQF.setText('{: 6f}'.format(self._deltaKL[0])) self.l_deltaKLQD.setText('{: 6f}'.format(self._deltaKL[1])) # ---------- chromaticity ---------- def _estimateChrom(self, use_ref=False): nom_SL = self._chromcorr.nominal_intstrengths.flatten() if use_ref: curr_SL = _np.array([self._reference['BO-Fam:PS-SF'], self._reference['BO-Fam:PS-SD']]) else: curr_SL = _np.array([self.norm_config['BO-Fam:PS-SF'], self.norm_config['BO-Fam:PS-SD']]) delta_SL = curr_SL - nom_SL return self._chromcorr.calculate_Chrom(delta_SL) def _handleChromSet(self): widget = self.sender() chrom = widget.objectName() dim = ' vertical ' if chrom == 'chromY' else ' horizantal ' new_value = widget.value() self._stack_command( widget, self._deltas[chrom], new_value, message='set'+dim+'chromaticity to {}'.format( new_value)) self._deltas[chrom] = new_value self._updateDeltaSL() def _updateDeltaSL(self): desired_Chrom = _np.array([self._deltas['chromX'], self._deltas['chromY']]) deltas = desired_Chrom - self._currChrom self._deltaSL = self._chromcorr.calculate_deltaSL( [deltas[0], deltas[1]]) self.l_deltaSLSF.setText('{: 4f}'.format(self._deltaSL[0])) self.l_deltaSLSD.setText('{: 4f}'.format(self._deltaSL[1])) self.norm_config['BO-Fam:PS-SF'] = \ self._reference['BO-Fam:PS-SF'] + self._deltaSL[0] self.norm_config['BO-Fam:PS-SD'] = \ self._reference['BO-Fam:PS-SD'] + self._deltaSL[1] self._updateStrenghtsWidget('sexts') self.verifySync() def _resetChromChanges(self): self._currChrom = self._estimateChrom(use_ref=True) self.sb_ChromX.setValue(self._currChrom[0]) self.sb_ChromY.setValue(self._currChrom[1]) self._deltaSL = [0.0, 0.0] self.l_deltaSLSF.setText('{: 6f}'.format(self._deltaSL[0])) self.l_deltaSLSD.setText('{: 6f}'.format(self._deltaSL[1])) # ---------- update methods ---------- def _updateReference(self, pstype): psnames = self._get_PSNames(pstype) for ps in psnames: self._reference[ps] = self.norm_config[ps] if pstype == 'corrs': self._resetOrbitChanges() elif pstype == 'quads': self._resetTuneChanges() elif pstype == 'sexts': self._resetChromChanges() else: self._resetOrbitChanges() self._resetTuneChanges() self._resetChromChanges() self.verifySync() def _updateRampConfig(self): if self.norm_config is not None: self.normConfigChanged.emit(self.time, _dcopy(self.norm_config)) def updateTime(self, time): """Update norm config time.""" self.time = time self.label_time.setText('<h2>T = '+str(time)+'ms</h2>') self.energy = self.ramp_config.ps_waveform_interp_energy(time) self._handleStrengtsLimits(self.cb_checklims.checkState()) self.verifySync() def updateLabel(self, label): """Update norm config label.""" self.norm_config['label'] = label self.label_description.setText('<h2>'+label+'</h2>') self.verifySync() @Slot(str, str) def updateSettings(self, tunecorr_configname, chromcorr_configname): self._tunecorr = BOTuneCorr(tunecorr_configname) self._chromcorr = BOChromCorr(chromcorr_configname) self._updateDeltaKL() self._estimateChrom(use_ref=True) self._updateDeltaSL() # ---------- handle undo redo stack ---------- def _stack_command(self, widget, old_value, new_value, message): global _flag_stack_next_command, _flag_stacking if _flag_stack_next_command and (old_value != new_value): _flag_stacking = True command = _UndoRedoSpinbox(widget, old_value, new_value, message) self._undo_stack.push(command) else: _flag_stack_next_command = True # ---------- helper methods ---------- def _get_PSNames(self, pstype=None): psnames = list() if pstype == 'corrs': psnames = _PSSearch.get_psnames({'sec': 'BO', 'dev': 'C(V|H)'}) elif pstype == 'quads': psnames = ['BO-Fam:PS-QF', 'BO-Fam:PS-QD'] elif pstype == 'sexts': psnames = ['BO-Fam:PS-SF', 'BO-Fam:PS-SD'] else: psnames = _PSSearch.get_psnames({'sec': 'BO', 'sub': 'Fam'}) psnames.extend(_PSSearch.get_psnames({'sec': 'BO', 'dev': 'QS'})) psnames.extend(_PSSearch.get_psnames({'sec': 'BO', 'dev': 'CH'})) psnames.extend(_PSSearch.get_psnames({'sec': 'BO', 'dev': 'CV'})) return psnames def _show_kicks_graph(self): strenghts_dict = _dcopy(self.norm_config) strenghts_dict.pop('label') graph = _ShowCorrectorKicks(self, self.time, strenghts_dict) graph.show()
class InsertNormalizedConfig(SiriusDialog): """Auxiliary window to insert a new normalized config.""" insertConfig = Signal(float, str, dict) def __init__(self, parent, ramp_config): """Initialize object.""" super().__init__(parent) self.setObjectName('BOApp') self.ramp_config = ramp_config self.setWindowTitle('Insert Normalized Configuration') self._setupUi() def _setupUi(self): # selection widgets self.rb_interp = QRadioButton('Interpolate') self.rb_confsrv = QRadioButton('Take value from Config Server') self.rb_create = QRadioButton('Create from template') # data widget self.config_data = QWidget() glay_data = QGridLayout(self.config_data) self.le_interp_label = QLineEdit(self) # interpolate self.le_confsrv_name = _ConfigLineEdit( parent=self, config_type='bo_normalized') # from ConfigDB self.le_confsrv_name.textChanged.connect( self._handleInsertExistingConfig) self.le_confsrv_name.setVisible(False) self.le_nominal_label = QLineEdit(self) # from template self.le_nominal_label.setVisible(False) self.sb_time = QDoubleSpinBoxPlus(self) self.sb_time.setMaximum(490) self.sb_time.setDecimals(3) self.bt_insert = QPushButton('Insert', self) self.bt_insert.setAutoDefault(False) self.bt_insert.setDefault(False) self.bt_insert.clicked.connect(self._emitConfigData) self.bt_cancel = QPushButton('Cancel', self) self.bt_cancel.setAutoDefault(False) self.bt_cancel.setDefault(False) self.bt_cancel.clicked.connect(self.close) glay_data.addWidget(QLabel('Label: ', self), 0, 0) glay_data.addWidget(self.le_interp_label, 0, 1) glay_data.addWidget(self.le_confsrv_name, 0, 1) glay_data.addWidget(self.le_nominal_label, 0, 1) glay_data.addWidget(QLabel('Time [ms]: ', self), 1, 0) glay_data.addWidget(self.sb_time, 1, 1) glay_data.addWidget(self.bt_cancel, 2, 0) glay_data.addWidget(self.bt_insert, 2, 1) # connect visibility signals self.rb_interp.toggled.connect(self.le_interp_label.setVisible) self.rb_interp.setChecked(True) self.rb_confsrv.toggled.connect(self.le_confsrv_name.setVisible) self.rb_create.toggled.connect(self.le_nominal_label.setVisible) # layout lay = QVBoxLayout() lay.addWidget(QLabel('<h4>Insert a Normalized Configuration</h4>', self), alignment=Qt.AlignCenter) lay.addWidget(self.rb_interp) lay.addWidget(self.rb_confsrv) lay.addWidget(self.rb_create) lay.addStretch() lay.addWidget(self.config_data) self.setLayout(lay) @Slot(str) def _handleInsertExistingConfig(self, configname): try: self.norm_config = ramp.BoosterNormalized() self.norm_config.name = configname self.norm_config.load() energy = self.norm_config[ramp.BoosterRamp.PSNAME_DIPOLE_REF] time = self.ramp_config.ps_waveform_interp_time(energy) self.sb_time.setValue(time) except _ConfigDBException as err: QMessageBox.critical(self, 'Error', str(err), QMessageBox.Ok) def _emitConfigData(self): time = self.sb_time.value() if self.le_interp_label.isVisible(): label = self.le_interp_label.text() psname2strength = dict() elif self.le_confsrv_name.isVisible(): label = self.le_confsrv_name.text() psname2strength = { _PVName(k).device_name: v for k, v, d in self.norm_config.value['pvs'] } elif self.le_nominal_label.isVisible(): label = self.le_nominal_label.text() psname2strength = \ self.ramp_config.ps_normalized_config_nominal_values self.insertConfig.emit(time, label, psname2strength) self.close()
def _setupUi(self): gl = QGridLayout(self) fig = mplt.figure() wid = MatplotlibWidget(fig, parent=self) wid.setObjectName('fig_result') wid.setStyleSheet('#fig_result{min-width: 25em;}') self.fig_res = wid gs = mgs.GridSpec(3, 1) gs.update(left=0.18, right=0.98, top=0.97, bottom=0.08, hspace=0.25) axes = wid.figure.add_subplot(gs[0, 0]) axes.set_xlabel('Index') axes.set_ylabel('Normalized Emit. [mm.mrad]') axes.grid(True) axes.set_aspect('auto') self.line_nemitx_tm = axes.plot( self.nemitx_tm, '-bo', lw=1, label='Hor. Trans. Mat.')[0] self.line_nemitx_parf = axes.plot( self.nemitx_parf, '--bd', lw=1, label='Hor. Parab. Fit')[0] self.line_nemity_tm = axes.plot( self.nemity_tm, '--ro', lw=1, label='Vert. Trans. Mat.')[0] self.line_nemity_parf = axes.plot( self.nemity_parf, '--rd', lw=1, label='Vert. Parab. Fit')[0] axes.legend(loc='best') axes = wid.figure.add_subplot(gs[1, 0]) axes.set_xlabel('Index') axes.set_ylabel(r'$\beta$ [m]') self.line_betax_tm = axes.plot( self.betax_tm, '-bo', lw=1, label='Hor. Trans. Mat.')[0] self.line_betax_parf = axes.plot( self.betax_parf, '--bd', lw=1, label='Hor. Parab. Fit')[0] self.line_betay_tm = axes.plot( self.betay_tm, '--ro', lw=1, label='Vert. Trans. Mat.')[0] self.line_betay_parf = axes.plot( self.betay_parf, '--rd', lw=1, label='Vert. Parab. Fit')[0] axes = wid.figure.add_subplot(gs[2, 0]) axes.set_xlabel('Index') axes.set_ylabel(r'$\alpha$') self.line_alphax_tm = axes.plot( self.alphax_tm, '-bo', lw=1, label='Hor. Trans. Mat.')[0] self.line_alphax_parf = axes.plot( self.alphax_parf, '--bd', lw=1, label='Hor. Parab. Fit')[0] self.line_alphay_tm = axes.plot( self.alphay_tm, '--ro', lw=1, label='Vert. Trans. Mat.')[0] self.line_alphay_parf = axes.plot( self.alphay_parf, '--rd', lw=1, label='Vert. Parab. Fit')[0] measlay = QVBoxLayout() gb = QGroupBox('QF3 Current [A]', self) measlay.addWidget(gb) gb.setLayout(QHBoxLayout()) spnbox = SiriusSpinbox( gb, _PVName('LI-01:PS-QF3:Current-SP').substitute( prefix=self._prefix)) lbl = SiriusLabel( gb, _PVName('LI-01:PS-QF3:Current-Mon').substitute( prefix=self._prefix)) spnbox.showStepExponent = False gb.layout().addWidget(spnbox) gb.layout().addWidget(lbl) gb.layout().setAlignment(Qt.AlignTop) gb = QGroupBox('Data Acquisition Configs.', self) fl = QFormLayout(gb) measlay.addWidget(gb) self.pb_start = QPushButton('Start', gb) self.pb_start.clicked.connect(self.pb_start_clicked) self.pb_stop = QPushButton('Stop', gb) self.pb_stop.clicked.connect(self.pb_stop_clicked) self.pb_stop.setEnabled(False) hbox_bts = QHBoxLayout() hbox_bts.addWidget(self.pb_start) hbox_bts.addWidget(self.pb_stop) fl.addRow(hbox_bts) self.cbbox_plane = QComboBox(gb) self.cbbox_plane.addItem('Horizontal') self.cbbox_plane.addItem('Vertical') fl.addRow(QLabel('Plane', gb), self.cbbox_plane) self.spbox_steps = QSpinBoxPlus(gb) self.spbox_steps.setValue(11) fl.addRow(QLabel('Nr Steps', gb), self.spbox_steps) self.spbox_samples = QSpinBoxPlus(gb) self.spbox_samples.setMinimum(1) self.spbox_samples.setValue(16) fl.addRow(QLabel('Nr Samples per step', gb), self.spbox_samples) self.spbox_outliers = QSpinBoxPlus(gb) self.spbox_outliers.setMinimum(0) self.spbox_outliers.setValue(12) fl.addRow(QLabel('Nr Outliers', gb), self.spbox_outliers) self.spbox_I_ini = QDoubleSpinBoxPlus(gb) self.spbox_I_ini.setMinimum(-4) self.spbox_I_ini.setMaximum(4) self.spbox_I_ini.setValue(-0.7) self.spbox_I_ini.setDecimals(3) fl.addRow(QLabel('Initial Current [A]', gb), self.spbox_I_ini) self.spbox_I_end = QDoubleSpinBoxPlus(gb) self.spbox_I_end.setMinimum(-4) self.spbox_I_end.setMaximum(4) self.spbox_I_end.setValue(0.7) self.spbox_I_end.setDecimals(3) fl.addRow(QLabel('Final Current [A]', gb), self.spbox_I_end) self.spbox_threshold = QDoubleSpinBoxPlus(gb) self.spbox_threshold.setMinimum(0) self.spbox_threshold.setMaximum(20) self.spbox_threshold.setValue(4) self.spbox_threshold.setDecimals(2) fl.addRow(QLabel('Max. Size Accpbl. [mm]', gb), self.spbox_threshold) measlay.setStretch(0, 2) measlay.setStretch(1, 8) anllay = QVBoxLayout() gb = QGroupBox('Analysis Configs.', self) vl = QVBoxLayout(gb) anllay.addWidget(gb) self.spbox_energy = QDoubleSpinBoxPlus(gb) self.spbox_energy.setMinimum(0.511) self.spbox_energy.setMaximum(200) self.spbox_energy.setValue(150) self.spbox_energy.setDecimals(2) self.pb_analyse_data = QPushButton('Analyse', gb) self.pb_analyse_data.clicked.connect(self.pb_analyse_data_clicked) hl = QHBoxLayout() hl.addWidget(QLabel('Energy [MeV]', gb)) hl.addWidget(self.spbox_energy) hl.addWidget(self.pb_analyse_data) vl.addLayout(hl) self.pb_save_data = QPushButton('Save Raw', gb) self.pb_save_data.clicked.connect(self.pb_save_data_clicked) self.pb_load_data = QPushButton('Load Raw', gb) self.pb_load_data.clicked.connect(self.pb_load_data_clicked) hl = QHBoxLayout() hl.addWidget(self.pb_save_data) hl.addWidget(self.pb_load_data) vl.addLayout(hl) self.logdisplay = PyDMLogDisplay(self, level=_log.INFO) vl.addWidget(self.logdisplay) resultsgb = QGroupBox('Results', self) gl2 = QGridLayout(resultsgb) gl2.addWidget(QLabel('Trans. Matrix', resultsgb), 0, 1, 1, 2) gl2.addWidget(QLabel('Parabola Fit', resultsgb), 0, 3, 1, 2) gl2.addWidget(QLabel('Hor.', resultsgb), 1, 1) gl2.addWidget(QLabel('Vert.', resultsgb), 1, 2) gl2.addWidget(QLabel('Hor.', resultsgb), 1, 3) gl2.addWidget(QLabel('Vert.', resultsgb), 1, 4) gl2.addWidget(QLabel('Norm. emitt.\n[mm.mrad]', resultsgb), 2, 0) gl2.addWidget(QLabel('beta [m]', resultsgb), 3, 0) gl2.addWidget(QLabel('alpha', resultsgb), 4, 0) for i, pref in enumerate(('nemit', 'beta', 'alpha')): for j, tp in enumerate(('x_tm', 'y_tm', 'x_parf', 'y_parf')): name = pref + tp lb = QLabel('----', resultsgb) setattr(self, 'lb_' + name, lb) gl2.addWidget(lb, i+2, j+1) wid = MatplotlibWidget(parent=self) axes = wid.figure.add_subplot(111) axes.set_xlabel('Quad. Current [A]') axes.set_ylabel('Beam Size [mm]') wid.figure.set_tight_layout(True) self.line_sigmax = axes.plot([], 'bo', lw=1, label='Horizontal')[0] self.line_sigmay = axes.plot([], 'ro', lw=1, label='Vertical')[0] self.line_fit = axes.plot([], '-k', lw=1)[0] wid.setObjectName('fig_sigma') wid.setStyleSheet('#fig_sigma{min-width: 25em;}') self.fig_sigma = wid gl.addWidget(self.plt_image, 0, 0, 2, 1) gl.addItem(measlay, 0, 1) gl.addWidget(self.fig_sigma, 1, 1) gl.addItem(anllay, 0, 2) gl.addWidget(resultsgb, 1, 2) gl.addWidget(self.fig_res, 0, 3, 2, 1)
class EmittanceMeasure(QWidget): def __init__(self, parent=None, place='LI', prefix=_VACA_PREFIX): super().__init__(parent=parent) self._place = place or 'LI' self._prefix = prefix self.setObjectName(self._place[0:2] + 'App') self._select_experimental_setup() self.nemitx_tm = [] self.nemity_tm = [] self.nemitx_parf = [] self.nemity_parf = [] self.betax_tm = [] self.betay_tm = [] self.betax_parf = [] self.betay_parf = [] self.alphax_tm = [] self.alphay_tm = [] self.alphax_parf = [] self.alphay_parf = [] self.measurement = None self.I_meas = None self.sigma = None self.plane_meas = None self._setupUi() def meas_emittance(self): self._acquire_data() self._perform_analysis() def _select_experimental_setup(self): if self._place.lower().startswith('li'): self.plt_image = ProcessImage( self, place='LI-Emittance', prefix=self._prefix) self.conv2kl = _NormFact.create('LI-01:MA-QF3') self.quad_I_sp = PV(_PVName( 'LI-01:PS-QF3:Current-SP').substitute(prefix=self._prefix)) self.quad_I_rb = PV(_PVName( 'LI-01:PS-QF3:Current-Mon').substitute(prefix=self._prefix)) self.DIST = 2.8775 self.QUAD_L = 0.112 if self._place.lower().startswith('tb-qd2a'): self.plt_image = ProcessImage( self, place='TB-Emittance', prefix=self._prefix) self.conv2kl = _NormFact.create('TB-02:MA-QD2A') self.quad_I_sp = PV(_PVName( 'TB-02:PS-QD2A:Current-SP').substitute(prefix=self._prefix)) self.quad_I_rb = PV(_PVName( 'TB-02:PS-QD2A:Current-RB').substitute(prefix=self._prefix)) self.DIST = 6.904 self.QUAD_L = 0.1 if self._place.lower().startswith('tb-qf2a'): self.plt_image = ProcessImage( self, place='TB-Emittance', prefix=self._prefix) self.conv2kl = _NormFact.create('TB-02:MA-QF2A') self.quad_I_sp = PV(_PVName( 'TB-02:PS-QF2A:Current-SP').substitute(prefix=self._prefix)) self.quad_I_rb = PV(_PVName( 'TB-02:PS-QF2A:Current-RB').substitute(prefix=self._prefix)) self.DIST = 6.534 self.QUAD_L = 0.1 def _acquire_data(self): samples = self.spbox_samples.value() outlier = self.spbox_outliers.value() if samples <= outlier: _log.warning( 'Number of samples must be larger than number o outliers.') _log.warning('Acquisition aborted.') return nsteps = self.spbox_steps.value() I_ini = self.spbox_I_ini.value() I_end = self.spbox_I_end.value() outs = outlier // 2 # outliers below median outg = outlier - outs # outliers above median self.line_sigmax.set_xdata([]) self.line_sigmax.set_ydata([]) self.line_sigmay.set_xdata([]) self.line_sigmay.set_ydata([]) self.line_fit.set_xdata([]) self.line_fit.set_ydata([]) self.fig_sigma.figure.canvas.draw() pl = 'y' if self.cbbox_plane.currentIndex() else 'x' curr_list = np.linspace(I_ini, I_end, nsteps) init_curr = self.quad_I_sp.value sigma = [] I_meas = [] for i, I in enumerate(curr_list): _log.info('setting quadrupole to {0:8.3f} A'.format(I)) if not SIMUL: self.quad_I_sp.put(I, wait=True) self._measuring.wait(5 if i else 15) j = 0 I_tmp = [] sig_tmp = [] while j < samples: if self._measuring.is_set(): self.pb_stop.setEnabled(False) self.pb_start.setEnabled(True) _log.info('Stopped') return _log.info(' sample {0:02d}'.format(j)) I_now = self.quad_I_rb.value cen_x, sigma_x, cen_y, sigma_y = self.plt_image.get_params() mu, sig = (cen_x, sigma_x) if pl == 'x' else (cen_y, sigma_y) max_size = self.spbox_threshold.value()*1e-3 if sig > max_size: self._measuring.wait(1) continue I_tmp.append(I_now) sig_tmp.append(abs(sig)) self._measuring.wait(0.5) j += 1 ind = np.argsort(sig_tmp) I_tmp = np.array(I_tmp)[ind] sig_tmp = np.array(sig_tmp)[ind] I_meas.extend(I_tmp[outs:-outg]) sigma.extend(sig_tmp[outs:-outg]) if pl == 'x': self.line_sigmax.set_xdata(I_meas) self.line_sigmax.set_ydata(np.array(sigma)*1e3) else: self.line_sigmay.set_xdata(I_meas) self.line_sigmay.set_ydata(np.array(sigma)*1e3) self.fig_sigma.figure.axes[0].set_xlim( [min(I_meas)*(1-DT*10), max(I_meas)*(1+DT*10)]) self.fig_sigma.figure.axes[0].set_ylim( [min(sigma)*(1-DT)*1e3, max(sigma)*(1+DT)*1e3]) self.fig_sigma.figure.canvas.draw() self._measuring.set() _log.info('Returning Quad to Initial Current') self.quad_I_sp.put(init_curr, wait=True) self.pb_stop.setEnabled(False) self.pb_start.setEnabled(True) _log.info('Finished!') self.I_meas = I_meas self.sigma = sigma self.plane_meas = pl def _perform_analysis(self): sigma = np.array(self.sigma) I_meas = np.array(self.I_meas) pl = self.plane_meas K1 = self._get_K1_from_I(I_meas) # Transfer Matrix nem, bet, alp = self._trans_matrix_analysis(K1, sigma, pl=pl) getattr(self, 'nemit' + pl + '_tm').append(nem) getattr(self, 'beta' + pl + '_tm').append(bet) getattr(self, 'alpha' + pl + '_tm').append(alp) # Parabola Fitting nem, bet, alp = self._thin_lens_approx(K1, sigma, pl=pl) getattr(self, 'nemit' + pl + '_parf').append(nem) getattr(self, 'beta' + pl + '_parf').append(bet) getattr(self, 'alpha' + pl + '_parf').append(alp) for pref in ('nemit', 'beta', 'alpha'): for var in ('_tm', '_parf'): tp = pref + pl + var yd = np.array(getattr(self, tp)) line = getattr(self, 'line_'+tp) line.set_xdata(np.arange(yd.shape[0])) line.set_ydata(yd) lb = getattr(self, 'lb_'+tp) lb.setText('{0:.3f}'.format(yd.mean())) params = [] for var in ('x_tm', 'y_tm', 'x_parf', 'y_parf'): params.extend(getattr(self, pref + var)) params = np.array(params) axes = getattr(self, 'line_' + pref + 'x_parf').axes axes.set_xlim([-0.1, params.shape[0]+0.1]) axes.set_ylim([params.min()*(1-DT), params.max()*(1+DT)]) self.fig_res.figure.canvas.draw() def _get_K1_from_I(self, I_meas): energy = self.spbox_energy.value() * 1e-3 # energy in GeV KL = self.conv2kl.conv_current_2_strength( I_meas, strengths_dipole=energy) return KL/self.QUAD_L def _trans_matrix_analysis(self, K1, sigma, pl='x'): Rx, Ry = self._get_trans_mat(K1) R = Rx if pl == 'x' else Ry pseudo_inv = (np.linalg.inv(np.transpose(R) @ R) @ np.transpose(R)) [s_11, s_12, s_22] = pseudo_inv @ (sigma*sigma) # s_11, s_12, s_22 = np.linalg.lstsq(R, sigma * sigma)[0] nemit, beta, alpha, gamma = self._twiss(s_11, s_12, s_22) return nemit, beta, alpha def _thin_lens_approx(self, K1, sigma, pl='x'): K1 = K1 if pl == 'x' else -K1 a, b, c = np.polyfit(K1, sigma*sigma, 2) yd = np.sqrt(np.polyval([a, b, c], K1)) self.line_fit.set_xdata(self.I_meas) self.line_fit.set_ydata(yd*1e3) self.fig_sigma.figure.canvas.draw() d = self.DIST + self.QUAD_L/2 l = self.QUAD_L s_11 = a/(d*l)**2 s_12 = (-b-2*d*l*s_11)/(2*l*d*d) s_22 = (c-s_11-2*d*s_12)/d**2 nemit, beta, alpha, gamma = self._twiss(s_11, s_12, s_22) return nemit, beta, alpha def _twiss(self, s_11, s_12, s_22): energy = self.spbox_energy.value() # energy in MeV emit = np.sqrt(abs(s_11 * s_22 - s_12 * s_12)) beta = s_11 / emit alpha = -s_12 / emit gamma = s_22 / emit nemit = emit * energy / E0 * 1e6 # in mm.mrad return nemit, beta, alpha, gamma def _get_trans_mat(self, K1): R = np.zeros((len(K1), 4, 4)) Rd = gettransmat('drift', L=self.DIST) for i, k1 in enumerate(K1): Rq = gettransmat('quad', L=self.QUAD_L, K1=k1) R[i] = np.dot(Rd, Rq) R11 = R[:, 0, 0].reshape(-1, 1) R12 = R[:, 0, 1].reshape(-1, 1) R33 = R[:, 2, 2].reshape(-1, 1) R34 = R[:, 2, 3].reshape(-1, 1) Rx = np.column_stack((R11*R11, 2*R11*R12, R12*R12)) Ry = np.column_stack((R33*R33, 2*R33*R34, R34*R34)) return Rx, Ry def _setupUi(self): gl = QGridLayout(self) fig = mplt.figure() wid = MatplotlibWidget(fig, parent=self) wid.setObjectName('fig_result') wid.setStyleSheet('#fig_result{min-width: 25em;}') self.fig_res = wid gs = mgs.GridSpec(3, 1) gs.update(left=0.18, right=0.98, top=0.97, bottom=0.08, hspace=0.25) axes = wid.figure.add_subplot(gs[0, 0]) axes.set_xlabel('Index') axes.set_ylabel('Normalized Emit. [mm.mrad]') axes.grid(True) axes.set_aspect('auto') self.line_nemitx_tm = axes.plot( self.nemitx_tm, '-bo', lw=1, label='Hor. Trans. Mat.')[0] self.line_nemitx_parf = axes.plot( self.nemitx_parf, '--bd', lw=1, label='Hor. Parab. Fit')[0] self.line_nemity_tm = axes.plot( self.nemity_tm, '--ro', lw=1, label='Vert. Trans. Mat.')[0] self.line_nemity_parf = axes.plot( self.nemity_parf, '--rd', lw=1, label='Vert. Parab. Fit')[0] axes.legend(loc='best') axes = wid.figure.add_subplot(gs[1, 0]) axes.set_xlabel('Index') axes.set_ylabel(r'$\beta$ [m]') self.line_betax_tm = axes.plot( self.betax_tm, '-bo', lw=1, label='Hor. Trans. Mat.')[0] self.line_betax_parf = axes.plot( self.betax_parf, '--bd', lw=1, label='Hor. Parab. Fit')[0] self.line_betay_tm = axes.plot( self.betay_tm, '--ro', lw=1, label='Vert. Trans. Mat.')[0] self.line_betay_parf = axes.plot( self.betay_parf, '--rd', lw=1, label='Vert. Parab. Fit')[0] axes = wid.figure.add_subplot(gs[2, 0]) axes.set_xlabel('Index') axes.set_ylabel(r'$\alpha$') self.line_alphax_tm = axes.plot( self.alphax_tm, '-bo', lw=1, label='Hor. Trans. Mat.')[0] self.line_alphax_parf = axes.plot( self.alphax_parf, '--bd', lw=1, label='Hor. Parab. Fit')[0] self.line_alphay_tm = axes.plot( self.alphay_tm, '--ro', lw=1, label='Vert. Trans. Mat.')[0] self.line_alphay_parf = axes.plot( self.alphay_parf, '--rd', lw=1, label='Vert. Parab. Fit')[0] measlay = QVBoxLayout() gb = QGroupBox('QF3 Current [A]', self) measlay.addWidget(gb) gb.setLayout(QHBoxLayout()) spnbox = SiriusSpinbox( gb, _PVName('LI-01:PS-QF3:Current-SP').substitute( prefix=self._prefix)) lbl = SiriusLabel( gb, _PVName('LI-01:PS-QF3:Current-Mon').substitute( prefix=self._prefix)) spnbox.showStepExponent = False gb.layout().addWidget(spnbox) gb.layout().addWidget(lbl) gb.layout().setAlignment(Qt.AlignTop) gb = QGroupBox('Data Acquisition Configs.', self) fl = QFormLayout(gb) measlay.addWidget(gb) self.pb_start = QPushButton('Start', gb) self.pb_start.clicked.connect(self.pb_start_clicked) self.pb_stop = QPushButton('Stop', gb) self.pb_stop.clicked.connect(self.pb_stop_clicked) self.pb_stop.setEnabled(False) hbox_bts = QHBoxLayout() hbox_bts.addWidget(self.pb_start) hbox_bts.addWidget(self.pb_stop) fl.addRow(hbox_bts) self.cbbox_plane = QComboBox(gb) self.cbbox_plane.addItem('Horizontal') self.cbbox_plane.addItem('Vertical') fl.addRow(QLabel('Plane', gb), self.cbbox_plane) self.spbox_steps = QSpinBoxPlus(gb) self.spbox_steps.setValue(11) fl.addRow(QLabel('Nr Steps', gb), self.spbox_steps) self.spbox_samples = QSpinBoxPlus(gb) self.spbox_samples.setMinimum(1) self.spbox_samples.setValue(16) fl.addRow(QLabel('Nr Samples per step', gb), self.spbox_samples) self.spbox_outliers = QSpinBoxPlus(gb) self.spbox_outliers.setMinimum(0) self.spbox_outliers.setValue(12) fl.addRow(QLabel('Nr Outliers', gb), self.spbox_outliers) self.spbox_I_ini = QDoubleSpinBoxPlus(gb) self.spbox_I_ini.setMinimum(-4) self.spbox_I_ini.setMaximum(4) self.spbox_I_ini.setValue(-0.7) self.spbox_I_ini.setDecimals(3) fl.addRow(QLabel('Initial Current [A]', gb), self.spbox_I_ini) self.spbox_I_end = QDoubleSpinBoxPlus(gb) self.spbox_I_end.setMinimum(-4) self.spbox_I_end.setMaximum(4) self.spbox_I_end.setValue(0.7) self.spbox_I_end.setDecimals(3) fl.addRow(QLabel('Final Current [A]', gb), self.spbox_I_end) self.spbox_threshold = QDoubleSpinBoxPlus(gb) self.spbox_threshold.setMinimum(0) self.spbox_threshold.setMaximum(20) self.spbox_threshold.setValue(4) self.spbox_threshold.setDecimals(2) fl.addRow(QLabel('Max. Size Accpbl. [mm]', gb), self.spbox_threshold) measlay.setStretch(0, 2) measlay.setStretch(1, 8) anllay = QVBoxLayout() gb = QGroupBox('Analysis Configs.', self) vl = QVBoxLayout(gb) anllay.addWidget(gb) self.spbox_energy = QDoubleSpinBoxPlus(gb) self.spbox_energy.setMinimum(0.511) self.spbox_energy.setMaximum(200) self.spbox_energy.setValue(150) self.spbox_energy.setDecimals(2) self.pb_analyse_data = QPushButton('Analyse', gb) self.pb_analyse_data.clicked.connect(self.pb_analyse_data_clicked) hl = QHBoxLayout() hl.addWidget(QLabel('Energy [MeV]', gb)) hl.addWidget(self.spbox_energy) hl.addWidget(self.pb_analyse_data) vl.addLayout(hl) self.pb_save_data = QPushButton('Save Raw', gb) self.pb_save_data.clicked.connect(self.pb_save_data_clicked) self.pb_load_data = QPushButton('Load Raw', gb) self.pb_load_data.clicked.connect(self.pb_load_data_clicked) hl = QHBoxLayout() hl.addWidget(self.pb_save_data) hl.addWidget(self.pb_load_data) vl.addLayout(hl) self.logdisplay = PyDMLogDisplay(self, level=_log.INFO) vl.addWidget(self.logdisplay) resultsgb = QGroupBox('Results', self) gl2 = QGridLayout(resultsgb) gl2.addWidget(QLabel('Trans. Matrix', resultsgb), 0, 1, 1, 2) gl2.addWidget(QLabel('Parabola Fit', resultsgb), 0, 3, 1, 2) gl2.addWidget(QLabel('Hor.', resultsgb), 1, 1) gl2.addWidget(QLabel('Vert.', resultsgb), 1, 2) gl2.addWidget(QLabel('Hor.', resultsgb), 1, 3) gl2.addWidget(QLabel('Vert.', resultsgb), 1, 4) gl2.addWidget(QLabel('Norm. emitt.\n[mm.mrad]', resultsgb), 2, 0) gl2.addWidget(QLabel('beta [m]', resultsgb), 3, 0) gl2.addWidget(QLabel('alpha', resultsgb), 4, 0) for i, pref in enumerate(('nemit', 'beta', 'alpha')): for j, tp in enumerate(('x_tm', 'y_tm', 'x_parf', 'y_parf')): name = pref + tp lb = QLabel('----', resultsgb) setattr(self, 'lb_' + name, lb) gl2.addWidget(lb, i+2, j+1) wid = MatplotlibWidget(parent=self) axes = wid.figure.add_subplot(111) axes.set_xlabel('Quad. Current [A]') axes.set_ylabel('Beam Size [mm]') wid.figure.set_tight_layout(True) self.line_sigmax = axes.plot([], 'bo', lw=1, label='Horizontal')[0] self.line_sigmay = axes.plot([], 'ro', lw=1, label='Vertical')[0] self.line_fit = axes.plot([], '-k', lw=1)[0] wid.setObjectName('fig_sigma') wid.setStyleSheet('#fig_sigma{min-width: 25em;}') self.fig_sigma = wid gl.addWidget(self.plt_image, 0, 0, 2, 1) gl.addItem(measlay, 0, 1) gl.addWidget(self.fig_sigma, 1, 1) gl.addItem(anllay, 0, 2) gl.addWidget(resultsgb, 1, 2) gl.addWidget(self.fig_res, 0, 3, 2, 1) def pb_save_data_clicked(self): if self.I_meas is None or self.sigma is None: msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setText("Could not Save") msg.setInformativeText( "There are no data saved in Memory. Make a measurement First.") msg.setWindowTitle("Warning") msg.resize(900, 300) msg.exec_() return fname = QFileDialog.getSaveFileName( self, 'Save file', '', 'Text Files (*.txt *.dat)') if fname[0]: self.save_to_file(fname[0]) def save_to_file(self, fname): header = 'Plane = {0:s}\n'.format(self.plane_meas) header += '{0:15s} {1:15s}'.format('Current [A]', 'Beam Size [m]') np.savetxt(fname, np.column_stack( (self.I_meas, self.sigma)), header=header, fmt='%-15.9f %-15.10f') def pb_load_data_clicked(self): fname = QFileDialog.getOpenFileName( self, 'Open file', '', 'Text Files (*.txt *.dat)') if fname[0]: self.load_from_file(fname[0]) def load_from_file(self, fname): try: self.I_meas, self.sigma = np.loadtxt( fname, skiprows=2, unpack=True) except (ValueError, TypeError): msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setText("Could not Load File") msg.setInformativeText( "The chosen file does not match the formatting.") msg.setWindowTitle("Warning") msg.resize(900, 300) msg.exec_() return with open(fname, 'r') as f: self.plane_meas = f.readline().split()[-1] if self.plane_meas == 'x': self.line_sigmax.set_xdata(self.I_meas) self.line_sigmax.set_ydata(np.array(self.sigma)*1e3) else: self.line_sigmay.set_xdata(self.I_meas) self.line_sigmay.set_ydata(np.array(self.sigma)*1e3) self.fig_sigma.figure.axes[0].set_xlim( [min(self.I_meas)*(1-DT*10), max(self.I_meas)*(1+DT*10)]) self.fig_sigma.figure.axes[0].set_ylim( [min(self.sigma)*(1-DT)*1e3, max(self.sigma)*(1+DT)*1e3]) self.fig_sigma.figure.canvas.draw() def pb_analyse_data_clicked(self): if self.I_meas is None or self.sigma is None: msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setText("Could Perform Analysis") msg.setInformativeText( "No data in memory. Please make a measurement or load the data.") msg.setWindowTitle("Warning") msg.resize(900, 300) msg.exec_() return self._perform_analysis() def pb_start_clicked(self): """ Slot documentation goes here. """ _log.info('Starting...') if self.measurement is not None and self.measurement.isAlive(): return self.pb_stop.setEnabled(True) self.pb_start.setEnabled(False) self._measuring = Event() self.measurement = Thread(target=self.meas_emittance, daemon=True) self.measurement.start() def pb_stop_clicked(self): """ Slot documentation goes here. """ _log.info('Stopping...') self._measuring.set()
class EnergyButton(QWidget): """Set dipole energy.""" def __init__(self, section, parent=None): """Setups widget interface.""" super().__init__(parent) self._section = section self.dips, self.mags = init_section(section.upper()) self._items_fail = [] self._items_success = [] self._setup_ui() color = QColor(get_appropriate_color(section.upper())) pal = self.palette() pal.setColor(QPalette.Background, color) self.setAutoFillBackground(True) self.setPalette(pal) def _setup_ui(self): self.setLayout(QVBoxLayout()) self.energy_value = QDoubleSpinBoxPlus(self) self.energy_value.setSingleStep(0.01) self.energy_value.setMinimum(self.lower_limit) self.energy_value.setMaximum(self.upper_limit) self.energy_value.setDecimals(4) if self.section == 'tb': sp_channel = 'TB-Fam:PS-B:Energy-RB' elif self.section == 'bo': sp_channel = 'BO-Fam:PS-B-1:Energy-RB' elif self.section == 'ts': sp_channel = 'TS-Fam:PS-B:Energy-RB' elif self.section == 'si': sp_channel = 'SI-Fam:PS-B1B2-1:Energy-RB' else: raise RuntimeError sp_channel = _PVName(sp_channel).substitute(prefix=_VACA_PREFIX) self.energy_sp = PyDMLabel(self) self.energy_sp.channel = sp_channel self.energy_sp.showUnits = True self._tree = PVNameTree( items=self.mags, tree_levels=('dis', 'mag_group'), parent=self) self._tree.tree.setHeaderHidden(True) self._tree.tree.setColumnCount(1) self._tree.check_all() self._tree.collapse_all() self.set_energy = QPushButton('Set', self) self.set_energy.clicked.connect(self._process) # forml = Q hbl = QHBoxLayout() # hbl.addStretch() hbl.addWidget(QLabel('<h4>New Energy:</h4> ', self)) hbl.addWidget(self.energy_value) self.layout().addLayout(hbl) hbl = QHBoxLayout() # hbl.addStretch() hbl.addWidget(QLabel('Current Energy: ', self)) hbl.addWidget(self.energy_sp) self.layout().addLayout(hbl) self.layout().addWidget(self._tree) self.layout().addWidget(self.set_energy) @property def section(self): return self._section @property def upper_limit(self): if self.section == 'tb': return 0.155 elif self.section == 'bo': return 0.160 elif self.section == 'ts': return 3.2 elif self.section == 'si': return 3.014 else: raise RuntimeError @property def lower_limit(self): if self.section == 'tb': return 0.0 elif self.section == 'bo': return 0.0 elif self.section == 'ts': return 0.0 elif self.section == 'si': return 0.0 else: raise RuntimeError def _process(self): self._items_success = [] self._items_fail = [] # Get selected PVs selected_pvs = set(self._tree.checked_items()) mags = [mag for mag in self.mags if mag in selected_pvs] if not mags: report = ReportDialog(['Select at least one PS!'], self) report.exec_() return pvs = self.dips + mags conn = EpicsConnector(pvs, parent=self) get_task = EpicsGetter(pvs, parent=self) get_task.itemRead.connect(self._read_success) get_task.itemNotRead.connect(self._read_fail) dlg = ProgressDialog( ['Connecting', 'Reading'], [conn, get_task], parent=self) ret = dlg.exec_() if ret == dlg.Rejected: return if self._items_fail: failed = ['Failed to read some PVs', ] failed += self._items_fail + ['Aborting!', ] report = ReportDialog(failed, self) report.exec_() return energy = self.energy_value.value() # remove dipole pvs, values = zip(*self._items_success[len(self.dips):]) delays = [0.0, ] * len(pvs) self._items_success = [] energies = [energy, ] * len(self.dips) dly_dips = [0.0, ] * len(self.dips) conn = EpicsConnector(self.dips, parent=self) set_dip = EpicsSetter(self.dips, energies, dly_dips, parent=self) sleep_task = EpicsWait([None, ]*10, wait_time=2.0, parent=self) check_dip = EpicsChecker(self.dips, energies, dly_dips, parent=self) check_dip.itemChecked.connect(self._check_status) dlg = ProgressDialog( ['Connecting', 'Setting Dipole', 'Waiting Dipole', 'Checking Dipole'], [conn, set_dip, sleep_task, check_dip], parent=self) ret = dlg.exec_() if ret == dlg.Rejected: return if self._items_fail: failed = ['Failed to set Dipole. Aborting!'] report = ReportDialog(failed, self) report.exec_() return conn = EpicsConnector(pvs, parent=self) set_mags = EpicsSetter(pvs, values, delays, parent=self) sleep_task = EpicsWait([None, ]*10, wait_time=2.0, parent=self) check_mags = EpicsChecker(pvs, values, delays, parent=self) check_mags.itemChecked.connect(self._check_status) dlg = ProgressDialog( ['Connecting to Magnets', 'Setting Magnets', 'Waiting Magnets', 'Checking Magnets'], [conn, set_mags, sleep_task, check_mags], parent=self) ret = dlg.exec_() if ret == dlg.Rejected: return failed = [] if self._items_fail: failed = ['Failed to set magnets:', ] + self._items_fail report = ReportDialog(failed, self) report.exec_() @Slot(str) def _read_fail(self, item): self._items_fail.append(item) @Slot(str, QVariant) def _read_success(self, item, value): self._items_success.append((item, value)) @Slot(str, bool) def _check_status(self, item, status): if status: self._items_success.append((item, True)) else: self._items_fail.append(item)