Source code for siriushla.as_ap_sofb.ioc_control.respmat

"""Define Controllers for the orbits displayed in the graphic."""

import pathlib as _pathlib
from datetime import datetime as _datetime
import numpy as _np
from qtpy.QtWidgets import QFileDialog, QGroupBox, QPushButton, QFormLayout, \
    QGridLayout, QVBoxLayout, QHBoxLayout, QMessageBox, QLabel, QWidget, \
    QTabWidget
from qtpy.QtCore import Qt
import qtawesome as qta

from pydm.widgets import PyDMPushButton, PyDMCheckbox
from siriuspy.sofb.csdev import ConstTLines
from siriuspy.clientconfigdb import ConfigDBClient, ConfigDBException
from siriushla.widgets.windows import create_window_from_widget
from siriushla.widgets import SiriusLedState, SiriusEnumComboBox, \
    SiriusConnectionSignal as _ConnSig, SiriusLabel, CAPushButton
from siriushla.util import connect_window, get_appropriate_color, \
    connect_newprocess
from siriushla.as_ap_configdb import LoadConfigDialog, SaveConfigDialog

from .respmat_enbllist import SelectionMatrix
from .base import BaseWidget
from ..graphics import SingularValues


[docs] class RespMatWidget(BaseWidget): DEFAULT_DIR = _pathlib.Path.home().as_posix() def __init__(self, parent, device, prefix='', acc='SI'): super().__init__(parent, device, prefix=prefix, acc=acc) self._enblrule = None if acc == 'SI': self._enblrule = ( '[{"name": "EnblRule", "property": "Enable", ' + '"expression": "not ch[0]", "channels": [{"channel": "' + self.devpref.substitute(propty='LoopState-Sts') + '", "trigger": true}]}]') self.setupui() self._config_type = acc.lower() + '_orbcorr_respm' self._client = ConfigDBClient(config_type=self._config_type) self.EXT = self._csorb.respmat_fname.split('.')[1] self.EXT_FLT = 'RespMat Files (*.{})'.format(self.EXT) self.last_dir = self.DEFAULT_DIR self._respmat_sp = _ConnSig( self.devpref.substitute(propty='RespMat-SP')) self._respmat_rb = _ConnSig( self.devpref.substitute(propty='RespMat-RB'))
[docs] def setupui(self): """.""" gbox = QGroupBox('Matrix', self) gbox.setObjectName('grbx') vbl = QVBoxLayout(gbox) vbl.setContentsMargins(0, 6, 0, 0) tabw = QTabWidget(gbox) tabw.setObjectName(self.acc+'Tab') vbl.addWidget(tabw) main_wid = self.get_main_widget(tabw) tabw.addTab(main_wid, 'Main') svs_wid = self.get_singular_values_widget(tabw) tabw.addTab(svs_wid, 'SVs') if self.acc != 'BO': meas_wid = self.get_measurement_widget(tabw) tabw.addTab(meas_wid, 'Meas') lay = QVBoxLayout() lay.setContentsMargins(0, 0, 0, 0) self.setLayout(lay) lay.addWidget(gbox)
[docs] def get_main_widget(self, parent): main_wid = QWidget(parent) main_lay = QVBoxLayout(main_wid) sel_gp = QGroupBox('Sel.') sel_gp.setLayout(QHBoxLayout()) sel_gp.layout().setContentsMargins(0, 0, 0, 0) sel_wid = self.get_selection_lists_widget(sel_gp) sel_gp.layout().addWidget(sel_wid) main_lay.addWidget(sel_gp) svld_gp = QGroupBox('Load and Save') svld_gp.setLayout(QHBoxLayout()) svld_gp.layout().setContentsMargins(0, 0, 0, 0) svld_wid = self.get_saveload_widget(svld_gp) svld_gp.layout().addWidget(svld_wid) main_lay.addWidget(svld_gp) return main_wid
[docs] def get_selection_lists_widget(self, parent): """.""" sel_wid = QWidget(parent) sel_lay = QHBoxLayout(sel_wid) icon = qta.icon('fa5s.hammer', color=get_appropriate_color(self.acc)) window = create_window_from_widget( SelectionMatrix, title=self.acc + ' - SOFB - Corrs and BPMs selection', icon=icon) btn = QPushButton('', sel_wid) btn.setObjectName('btn') btn.setIcon(qta.icon('fa5s.tasks')) btn.setToolTip('Open window to select BPMs and correctors') btn.setStyleSheet( '#btn{min-width:3.8em; max-width:3.8em;\ min-height:2em; max-height:2em; icon-size:25px;}') connect_window( btn, window, None, device=self.device, prefix=self.prefix, acc=self.acc, rules=self._enblrule) sel_lay.addWidget(btn) lay = QVBoxLayout() sel_lay.addStretch() sel_lay.addLayout(lay) pdm_cbx = SiriusEnumComboBox( sel_wid, self.devpref.substitute(propty='RespMatMode-Sel')) pdm_cbx.rules = self._enblrule pdm_lbl = SiriusLabel( sel_wid, self.devpref.substitute(propty='RespMatMode-Sts')) hlay = QHBoxLayout() hlay.addWidget(pdm_cbx) hlay.addWidget(pdm_lbl) lay.addLayout(hlay) if self.acc in {'SI', 'BO'}: hlay = QHBoxLayout() lay.addLayout(hlay) pdm_chbx = PyDMCheckbox( sel_wid, self.devpref.substitute(propty='RFEnbl-Sel')) pdm_chbx.rules = self._enblrule pdm_chbx.setText('use RF') pdm_led = SiriusLedState( sel_wid, self.devpref.substitute(propty='RFEnbl-Sts')) hlay.addWidget(pdm_chbx) hlay.addWidget(pdm_led) btn = QPushButton('', sel_wid) btn.setToolTip('Visualize RespMat') btn.setIcon(qta.icon('mdi.chart-line')) btn.setObjectName('btn') btn.setStyleSheet('#btn{max-width:40px; icon-size:40px;}') connect_newprocess( btn, [f'sirius-hla-{self.acc.lower():s}-ap-sofb.py', '--matrix']) sel_lay.addWidget(btn) return sel_wid
[docs] def get_singular_values_widget(self, parent): """.""" svs_wid = QWidget(parent) svs_lay = QGridLayout(svs_wid) lbl = QLabel('Min. SV: ') wid = self.create_pair( svs_wid, 'MinSingValue', rules=self._enblrule) svs_lay.addWidget(lbl, 0, 0) svs_lay.addWidget(wid, 0, 1) lbl = QLabel('Tikhonov: ') wid = self.create_pair( svs_wid, 'TikhonovRegConst', rules=self._enblrule) svs_lay.addWidget(lbl, 1, 0) svs_lay.addWidget(wid, 1, 1) lbl = QLabel('Nr Sing Vals') lbls = SiriusLabel( svs_wid, self.devpref.substitute(propty='NrSingValues-Mon')) btn = QPushButton('', svs_wid) btn.setToolTip('Check Singular Values') btn.setIcon(qta.icon('mdi.chart-line')) btn.setObjectName('btn') btn.setStyleSheet('#btn{max-width:30px; icon-size:30px;}') hbl = QHBoxLayout() hbl.addWidget(btn) hbl.addStretch() hbl.addWidget(lbl) hbl.addWidget(lbls) svs_lay.addLayout(hbl, 2, 0, 1, 2) Window = create_window_from_widget( SingularValues, title='Check Singular Values') connect_window( btn, Window, svs_wid, device=self.device, prefix=self.prefix) return svs_wid
[docs] def get_measurement_widget(self, parent): """.""" meas_wid = QWidget(parent) meas_lay = QVBoxLayout(meas_wid) strt = PyDMPushButton( meas_wid, init_channel=self.devpref.substitute(propty="MeasRespMat-Cmd"), pressValue=ConstTLines.MeasRespMatCmd.Start) strt.rules = self._enblrule strt.setToolTip('Start Measurement') strt.setIcon(qta.icon('fa5s.play')) strt.setObjectName('strt') strt.setStyleSheet( '#strt{min-width:25px; max-width:25px; icon-size:20px;}') stop = PyDMPushButton( meas_wid, init_channel=self.devpref.substitute(propty="MeasRespMat-Cmd"), pressValue=ConstTLines.MeasRespMatCmd.Stop) stop.rules = self._enblrule stop.setToolTip('Stop Measurement') stop.setIcon(qta.icon('fa5s.stop')) stop.setObjectName('stop') stop.setStyleSheet( '#stop{min-width:25px; max-width:25px; icon-size:20px;}') rst = PyDMPushButton( meas_wid, init_channel=self.devpref.substitute(propty="MeasRespMat-Cmd"), pressValue=ConstTLines.MeasRespMatCmd.Reset) rst.rules = self._enblrule rst.setToolTip('Reset Measurement Status') rst.setIcon(qta.icon('fa5s.sync')) rst.setObjectName('conf') rst.setStyleSheet( '#conf{min-width:25px; max-width:25px; icon-size:20px;}') lbl = SiriusLabel( meas_wid, self.devpref.substitute(propty='MeasRespMat-Mon')) lbl.setAlignment(Qt.AlignCenter) hbl = QHBoxLayout() hbl.setSpacing(8) meas_lay.addLayout(hbl) hbl.addWidget(strt) hbl.addWidget(stop) hbl.addWidget(rst) hbl.addStretch() hbl.addWidget(lbl) fml = QFormLayout() meas_lay.addSpacing(20) meas_lay.addLayout(fml) lbl = QLabel('CH [urad]', meas_wid) wid = self.create_pair( meas_wid, 'MeasRespMatKickCH', rules=self._enblrule) fml.addRow(lbl, wid) lbl = QLabel('CV [urad]', meas_wid) wid = self.create_pair( meas_wid, 'MeasRespMatKickCV', rules=self._enblrule) fml.addRow(lbl, wid) if self.acc in {'SI', 'BO'}: lbl = QLabel('RF [Hz]', meas_wid) wid = self.create_pair( meas_wid, 'MeasRespMatKickRF', rules=self._enblrule) fml.addRow(lbl, wid) lbl = QLabel('Wait [s]', meas_wid) lbl.setToolTip('Time to wait between kicks') wid = self.create_pair( meas_wid, 'MeasRespMatWait', rules=self._enblrule) fml.addRow(lbl, wid) return meas_wid
[docs] def get_saveload_widget(self, parent): """.""" svld_wid = QWidget(parent) svld_lay = QGridLayout(svld_wid) lbl = QLabel('Load:', svld_wid) svld_lay.addWidget(lbl, 0, 0, alignment=Qt.AlignRight) pbtn = CAPushButton('', svld_wid) pbtn.rules = self._enblrule pbtn.setIcon(qta.icon('mdi.file-upload-outline')) pbtn.setToolTip('Load RespMat from file') pbtn.clicked.connect(self._load_respmat_from_file) svld_lay.addWidget(pbtn, 0, 1) pbtn = CAPushButton('', svld_wid) pbtn.rules = self._enblrule pbtn.setIcon(qta.icon('mdi.cloud-upload-outline')) pbtn.setToolTip('Load RespMat from ServConf') pbtn.clicked.connect(self._open_load_config_servconf) svld_lay.addWidget(pbtn, 0, 2) lbl = QLabel('Save:', svld_wid) svld_lay.addWidget(lbl, 0, 3, alignment=Qt.AlignRight) pbtn = QPushButton('', svld_wid) pbtn.setIcon(qta.icon('mdi.file-download-outline')) pbtn.setToolTip('Save RespMat to file') pbtn.clicked.connect(self._save_respmat_to_file) svld_lay.addWidget(pbtn, 0, 4) pbtn = QPushButton('', svld_wid) pbtn.setIcon(qta.icon('mdi.cloud-download-outline')) pbtn.setToolTip('Save RespMat to ServConf') pbtn.clicked.connect(self._open_save_config_servconf) svld_lay.addWidget(pbtn, 0, 5) self.respmat_label = QLabel('') svld_lay.addWidget(self.respmat_label, 1, 0, 1, 5) svld_lay.setRowStretch(2, 10) return svld_wid
def _save_respmat_to_file(self, _): header = '# ' + _datetime.now().strftime('%Y/%m/%d-%H:%M:%S') + '\n' if self.acc in {'SI', 'BO'}: header += '# (BPMX, BPMY) [um] x (CH, CV, RF) [urad, Hz]' + '\n' else: header += '# (BPMX, BPMY) [um] x (CH, CV) [urad]' + '\n' filename = QFileDialog.getSaveFileName( caption='Define a File Name to Save the Response Matrix', directory=self.last_dir, filter=self.EXT_FLT) fname = filename[0] if not fname: return fname += '' if fname.endswith(self.EXT) else ('.' + self.EXT) respm = self._respmat_rb.getvalue() respm = respm.reshape(-1, self._csorb.nr_corrs) _np.savetxt(fname, respm, header=header) def _load_respmat_from_file(self): filename = QFileDialog.getOpenFileName( caption='Select a Response Matrix File.', directory=self.last_dir, filter=self.EXT_FLT) if not filename[0]: return respm = _np.loadtxt(filename[0]) self._respmat_sp.send_value_signal[_np.ndarray].emit(respm.flatten()) self.respmat_label.setText('Loaded from file: \n\n' + filename[0]) def _open_load_config_servconf(self): win = LoadConfigDialog(self._config_type, self) win.configname.connect(self._set_respm) win.show() def _set_respm(self, confname): data = self._client.get_config_value(confname) self._respmat_sp.send_value_signal[_np.ndarray].emit( _np.array(data).flatten()) self.respmat_label.setText('Loaded from ServConf: \n\n' + confname) def _open_save_config_servconf(self): win = SaveConfigDialog(self._config_type, self) win.configname.connect(self._save_respm) win.show() def _save_respm(self, confname): val = self._respmat_rb.getvalue() val = val.reshape(-1, self._csorb.nr_corrs) try: self._client.insert_config(confname, val.tolist()) except (ConfigDBException, TypeError) as err: QMessageBox.warning(self, 'Warning', str(err), QMessageBox.Ok)