wip: digital twin
This commit is contained in:
@@ -4,7 +4,7 @@ import numpy as np
|
||||
from bec_lib import bec_logger
|
||||
|
||||
os.environ["USE_XRT"] = "False"
|
||||
import debye_bec.bec_widgets.widgets.digital_twin.x01da_parameters as bl
|
||||
import debye_bec.bec_widgets.widgets.x01da_parameters as bl
|
||||
|
||||
def calc_surfaces(cfg):
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import numpy as np
|
||||
from bec_lib import bec_logger
|
||||
|
||||
os.environ["USE_XRT"] = "False"
|
||||
import debye_bec.bec_widgets.widgets.digital_twin.x01da_parameters as bl
|
||||
import debye_bec.bec_widgets.widgets.x01da_parameters as bl
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import numpy as np
|
||||
import debye_bec.bec_widgets.widgets.digital_twin.x01da_parameters as bl
|
||||
import debye_bec.bec_widgets.widgets.x01da_parameters as bl
|
||||
|
||||
def calc_sideview(cfg):
|
||||
|
||||
|
||||
@@ -1,40 +1,54 @@
|
||||
"""
|
||||
Digital Twin: Custom BEC widget to support the beamline alignment.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import re
|
||||
import datetime
|
||||
import numpy as np
|
||||
from scipy.interpolate import UnivariateSpline
|
||||
from xrt.backends.raycing.physconsts import CHeVcm, AVOGADRO
|
||||
from bec_lib import bec_logger
|
||||
|
||||
# pylint: disable=E0611
|
||||
from qtpy.QtWidgets import (
|
||||
QWidget, QVBoxLayout, QHBoxLayout, QLabel,
|
||||
QApplication, QLayout, QGroupBox
|
||||
QWidget,
|
||||
QVBoxLayout,
|
||||
QHBoxLayout,
|
||||
QApplication,
|
||||
QLayout,
|
||||
)
|
||||
# pylint: disable=E0611
|
||||
from qtpy.QtCore import Qt, QTimer
|
||||
from qtpy.QtGui import QColor, QFont, QBrush
|
||||
from qtpy.QtCore import (
|
||||
Qt,
|
||||
QTimer,
|
||||
)
|
||||
from qtpy.QtGui import (
|
||||
QColor,
|
||||
QBrush,
|
||||
)
|
||||
import pyqtgraph as pg
|
||||
|
||||
from xrt.backends.raycing.physconsts import CHeVcm, AVOGADRO
|
||||
|
||||
from bec_widgets.utils.bec_widget import BECWidget
|
||||
from bec_widgets.utils.error_popups import SafeSlot
|
||||
|
||||
from debye_bec.bec_widgets.widgets.qt_widgets import InputNumberField, ComboBox, Group, NumberIndicator
|
||||
|
||||
from debye_bec.bec_widgets.widgets.qt_widgets import (
|
||||
InputNumberField,
|
||||
ComboBox,
|
||||
Group,
|
||||
NumberIndicator,
|
||||
Mover,
|
||||
)
|
||||
from debye_bec.bec_widgets.widgets.digital_twin.calculate_positions import calc_positions
|
||||
from debye_bec.bec_widgets.widgets.digital_twin.calculate_sideview import calc_sideview
|
||||
from debye_bec.bec_widgets.widgets.digital_twin.calc_surfaces import calc_surfaces
|
||||
|
||||
import debye_bec.bec_widgets.widgets.digital_twin.x01da_parameters as bl
|
||||
import debye_bec.bec_widgets.widgets.x01da_parameters as bl
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
class DigitalTwin(BECWidget, QWidget):
|
||||
"""
|
||||
A simple BEC widget with:
|
||||
- Two numeric inputs (A, B)
|
||||
- Two computed outputs (Sum, Product)
|
||||
- A live plot that updates every second
|
||||
Main widget of Digital Twin
|
||||
"""
|
||||
|
||||
PLUGIN = True
|
||||
@@ -53,65 +67,94 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
self.sideview_plot = SideviewPlot()
|
||||
self.surface_plots = SurfacePlots()
|
||||
self.positions = PositionsPanel()
|
||||
# self.mover = MoverPanel(dev=self.dev)
|
||||
|
||||
self.root_layout.addWidget(self.input, stretch=1, alignment=Qt.AlignTop) # type: ignore
|
||||
self.plot_layout.addWidget(self.sideview_plot) # type: ignore
|
||||
self.plot_layout.addWidget(self.surface_plots) # type: ignore
|
||||
self.root_layout.addWidget(self.plot_widget, stretch=1, alignment=Qt.AlignTop) # type: ignore
|
||||
self.root_layout.addWidget(self.positions, stretch=1, alignment=Qt.AlignTop) # type: ignore
|
||||
# self.root_layout.addWidget(self.mover, stretch=1, alignment=Qt.AlignTop) # type: ignore
|
||||
|
||||
self.setLayout(self.root_layout)
|
||||
self.setWindowTitle("Digital Twin")
|
||||
self.resize(1800, 800)
|
||||
|
||||
self.input.energy.value_changed_connect(self.calc_bragg_angle)
|
||||
self.input.sldi_hacc.value_changed_connect(self.calc_positions)
|
||||
self.input.sldi_vacc.value_changed_connect(self.calc_positions)
|
||||
self.input.cm_stripe.activated_connect(self.calc_positions)
|
||||
self.input.cm_pitch.value_changed_connect(self.calc_positions)
|
||||
self.input.mo1_mode.activated_connect(self.calc_positions)
|
||||
self.input.fm_stripe.activated_connect(self.calc_positions)
|
||||
self.input.fm_pitch.value_changed_connect(self.calc_positions)
|
||||
self.input.smpl.value_changed_connect(self.calc_positions)
|
||||
|
||||
self.input.energy.value_changed_connect(self.calc_crit_angle)
|
||||
self.input.cm_stripe.activated_connect(self.calc_crit_angle)
|
||||
|
||||
self.input.mo1_xtal.activated_connect(self.calc_bragg_angle)
|
||||
|
||||
self.input.mo1_mode.activated_connect(self.update_mono_mode)
|
||||
|
||||
self.input.fm_stripe.activated_connect(self.calc_ideal_fm_pitch)
|
||||
self.input.smpl.value_changed_connect(self.calc_ideal_fm_pitch)
|
||||
|
||||
self.input.energy.value_changed_connect(self.calc_cm_reflectivity)
|
||||
self.input.cm_pitch.value_changed_connect(self.calc_cm_reflectivity)
|
||||
self.input.cm_stripe.activated_connect(self.calc_cm_reflectivity)
|
||||
self.input.fm_pitch.value_changed_connect(self.calc_fm_reflectivity)
|
||||
self.input.fm_stripe.activated_connect(self.calc_fm_reflectivity)
|
||||
self.input.energy.value_changed_connect(self.calc_cm_reflectivity)
|
||||
|
||||
self.input.energy.value_changed_connect(self.calc_energy_resolution)
|
||||
self.input.mo1_xtal.activated_connect(self.calc_energy_resolution)
|
||||
self.input.energy.value_changed_connect(self.calc_assistant)
|
||||
self.input.sldi_hacc.value_changed_connect(self.calc_assistant)
|
||||
self.input.sldi_vacc.value_changed_connect(self.calc_assistant)
|
||||
self.input.cm_stripe.activated_connect(self.calc_assistant)
|
||||
self.input.cm_pitch.value_changed_connect(self.calc_assistant)
|
||||
self.input.mo1_mode.activated_connect(self.calc_assistant)
|
||||
self.input.mo1_xtal.activated_connect(self.calc_assistant)
|
||||
self.input.fm_stripe.activated_connect(self.calc_assistant)
|
||||
self.input.fm_pitch.value_changed_connect(self.calc_assistant)
|
||||
self.input.smpl.value_changed_connect(self.calc_assistant)
|
||||
|
||||
self.bragg_angle = 0
|
||||
self.calc_bragg_angle()
|
||||
self.calc_ideal_fm_pitch()
|
||||
self.calc_crit_angle()
|
||||
self.calc_assistant_sideview()
|
||||
self.calc_reality_sideview()
|
||||
self.calc_cm_reflectivity()
|
||||
self.calc_fm_reflectivity()
|
||||
self.calc_energy_resolution()
|
||||
|
||||
# Initialize all values
|
||||
self.calc_assistant(identifier='init')
|
||||
|
||||
# Timer: update plot every 1 second
|
||||
self._timer = QTimer(self)
|
||||
self._timer.setInterval(1000)
|
||||
self._timer.timeout.connect(self.calc_reality_sideview)
|
||||
self._timer.timeout.connect(self.calc_reality)
|
||||
# TODO: Check if I need to stop the timer if the widget is closed?
|
||||
self._timer.start()
|
||||
|
||||
def calc_energy_resolution(self, *args):
|
||||
@SafeSlot()
|
||||
def calc_assistant(self, *args, **kwargs):
|
||||
identifier = kwargs['identifier']
|
||||
match identifier:
|
||||
case 'init':
|
||||
self.calc_mo1_bragg_angle()
|
||||
self.calc_cm_crit_pitch()
|
||||
self.calc_cm_reflectivity()
|
||||
self.calc_fm_reflectivity()
|
||||
self.calc_cm_fm_harm_suppr()
|
||||
self.calc_fm_ideal_pitch()
|
||||
self.calc_mo1_energy_resolution()
|
||||
case 'energy':
|
||||
self.calc_mo1_bragg_angle()
|
||||
self.calc_cm_crit_pitch()
|
||||
self.calc_cm_reflectivity()
|
||||
self.calc_fm_reflectivity()
|
||||
self.calc_cm_fm_harm_suppr()
|
||||
self.calc_mo1_energy_resolution()
|
||||
case 'cm_stripe':
|
||||
self.calc_cm_crit_pitch()
|
||||
self.calc_cm_reflectivity()
|
||||
self.calc_cm_fm_harm_suppr()
|
||||
case 'cm_pitch':
|
||||
self.calc_cm_reflectivity()
|
||||
self.calc_cm_fm_harm_suppr()
|
||||
case 'mo1_mode':
|
||||
self.update_mo1_mode()
|
||||
case 'mo1_xtal':
|
||||
self.calc_mo1_bragg_angle()
|
||||
self.calc_mo1_energy_resolution()
|
||||
case 'fm_stripe':
|
||||
self.calc_fm_reflectivity()
|
||||
self.calc_cm_fm_harm_suppr()
|
||||
self.calc_fm_ideal_pitch()
|
||||
case 'smpl':
|
||||
self.calc_fm_ideal_pitch()
|
||||
self.calc_positions()
|
||||
self.calc_assistant_sideview()
|
||||
self.calc_assistant_surfaces()
|
||||
|
||||
@SafeSlot()
|
||||
def calc_reality(self):
|
||||
config = self.get_reality_config()
|
||||
beam = calc_sideview(config)
|
||||
self.sideview_plot.data['reality']['x'] = beam['Z']
|
||||
self.sideview_plot.data['reality']['y'] = beam['Y']
|
||||
self.sideview_plot.update_curves()
|
||||
surfaces = calc_surfaces(config)
|
||||
self.surface_plots.update_surfaces(scene='reality', data=surfaces)
|
||||
|
||||
def calc_mo1_energy_resolution(self, *args, **kwargs):
|
||||
xtal = self.input.mo1_xtal.currentText().translate(str.maketrans('', '', '()')) # Remove brackets from xtal name to conform with parameters
|
||||
index = bl.mo1.xtal.index(xtal)
|
||||
crystal = bl.mo1.material1[index]
|
||||
@@ -139,7 +182,7 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
|
||||
self.input.mo1_eres.setValue(dE)
|
||||
|
||||
def calc_cm_reflectivity(self, *args):
|
||||
def calc_cm_reflectivity(self):
|
||||
index = bl.cm.surface.index(self.input.cm_stripe.currentText())
|
||||
rs, rp = bl.cm.material[index].get_amplitude(
|
||||
self.input.energy.value(),
|
||||
@@ -154,11 +197,7 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
self.input.cm_refl_harm.setValue(100 * abs(rs)**2)
|
||||
self.input.cm_refl_harm.setLabel(f"Reflectivity at \n{3 * self.input.energy.value():.0f} eV")
|
||||
|
||||
harm_suppr = (self.input.cm_refl.value() * self.input.fm_refl.value()) / (self.input.cm_refl_harm.value() * self.input.fm_refl_harm.value())
|
||||
self.input.cm_fm_harm_suppr.setValue(harm_suppr)
|
||||
self.input.cm_fm_harm_suppr.setLabel(f"Total Suppression Factor at {3 * self.input.energy.value():.0f} eV")
|
||||
|
||||
def calc_fm_reflectivity(self, *args):
|
||||
def calc_fm_reflectivity(self):
|
||||
if self.input.fm_stripe.currentText() in ('Rh (toroid)', 'Pt (toroid)'):
|
||||
surface = bl.fm.surfaceToroid
|
||||
material = bl.fm.materialToroid
|
||||
@@ -182,6 +221,7 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
self.input.fm_refl_harm.setValue(100 * abs(rs)**2)
|
||||
self.input.fm_refl_harm.setLabel(f"Reflectivity at \n{3 * self.input.energy.value():.0f} eV")
|
||||
|
||||
def calc_cm_fm_harm_suppr(self):
|
||||
harm_suppr = (self.input.cm_refl.value() * self.input.fm_refl.value()) / (self.input.cm_refl_harm.value() * self.input.fm_refl_harm.value())
|
||||
self.input.cm_fm_harm_suppr.setValue(harm_suppr)
|
||||
self.input.cm_fm_harm_suppr.setLabel(f"Total Suppression Factor at {3 * self.input.energy.value():.0f} eV")
|
||||
@@ -203,8 +243,7 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
}
|
||||
# logger.info(f'Config created: {config}')
|
||||
return config
|
||||
|
||||
# TODO Needs to run in a loop in a separate thread due to the long time it takes to get the values from self.dev...
|
||||
|
||||
def get_reality_config(self):
|
||||
if abs(self.dev.mo1_trx.read()['mo1_trx']['value']) > 5:
|
||||
mo1_mode = 'Monochromatic'
|
||||
@@ -221,6 +260,7 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
for name, low, high in zip(bl.cm.surface, bl.cm.limOptX[0], bl.cm.limOptX[1]):
|
||||
if low <= cm_trx <= high:
|
||||
cm_stripe = name
|
||||
cm_pitch = -self.dev.cm_rotx.read()['cm_rotx']['value'] * 1e-3
|
||||
fm_trx = -self.dev.fm_trx.read()['fm_trx']['value']
|
||||
fm_stripe = None
|
||||
for name, low, high in zip(bl.fm.surfaceFlat, bl.fm.limOptXFlat[1], bl.fm.limOptXFlat[0]):
|
||||
@@ -229,16 +269,18 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
for name, low, high in zip(bl.fm.surfaceToroid, bl.fm.limOptXToroid[1], bl.fm.limOptXToroid[0]):
|
||||
if low <= fm_trx <= high:
|
||||
fm_stripe = name + ' (toroid)'
|
||||
fm_pitch = -self.dev.fm_rotx.read()['fm_rotx']['value'] * 1e-3
|
||||
fm_pitch_real = 2 * cm_pitch - fm_pitch
|
||||
config = { # Config in SI units!
|
||||
'energy' : mo1_bragg['mo1_bragg']['value'],
|
||||
'h_acc' : h_acc,
|
||||
'v_acc' : v_acc,
|
||||
'cm_pitch' : -self.dev.cm_rotx.read()['cm_rotx']['value'] * 1e-3,
|
||||
'cm_pitch' : cm_pitch,
|
||||
'cm_stripe' : cm_stripe,
|
||||
'mo1_mode' : mo1_mode,
|
||||
'mo1_xtal' : mo1_bragg['mo1_bragg_crystal_current_xtal_string']['value'],
|
||||
'mo1_bragg' : mo1_bragg['mo1_bragg_angle']['value']/180*np.pi,
|
||||
'fm_pitch' : -self.dev.fm_rotx.read()['fm_rotx']['value'] * 1e-3,
|
||||
'fm_pitch' : fm_pitch_real,
|
||||
'fm_stripe' : fm_stripe,
|
||||
'fm_gain_height' : 1,
|
||||
'smpl' : self.dev.ot_es1_trz.read()['ot_es1_trz']['value'],
|
||||
@@ -247,35 +289,19 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
return config
|
||||
|
||||
@SafeSlot()
|
||||
def calc_assistant_sideview(self, *args):
|
||||
def calc_assistant_sideview(self):
|
||||
beam = calc_sideview(self.get_assistant_config())
|
||||
self.sideview_plot.data['assistant']['x'] = beam['Z']
|
||||
self.sideview_plot.data['assistant']['y'] = beam['Y']
|
||||
self.sideview_plot.update_curves()
|
||||
|
||||
@SafeSlot()
|
||||
def calc_reality_sideview(self):
|
||||
# logger.info('Update reality plot')
|
||||
beam = calc_sideview(self.get_reality_config())
|
||||
self.sideview_plot.data['reality']['x'] = beam['Z']
|
||||
self.sideview_plot.data['reality']['y'] = beam['Y']
|
||||
self.sideview_plot.update_curves()
|
||||
|
||||
# TODO Move to different place
|
||||
self.calc_reality_surfaces()
|
||||
|
||||
@SafeSlot()
|
||||
def calc_assistant_surfaces(self, *args):
|
||||
def calc_assistant_surfaces(self):
|
||||
surfaces = calc_surfaces(self.get_assistant_config())
|
||||
self.surface_plots.update_surfaces(scene='assistant', data=surfaces)
|
||||
|
||||
@SafeSlot()
|
||||
def calc_reality_surfaces(self, *args):
|
||||
surfaces = calc_surfaces(self.get_reality_config())
|
||||
self.surface_plots.update_surfaces(scene='reality', data=surfaces)
|
||||
|
||||
@SafeSlot()
|
||||
def calc_positions(self, *args):
|
||||
def calc_positions(self):
|
||||
out = calc_positions(self.get_assistant_config())
|
||||
|
||||
self.positions.sldi_gapx.setValue(out['sldi_gapx']['value'])
|
||||
@@ -299,12 +325,8 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
self.positions.ot_rotx.setValue(out['ot_rotx']['value'])
|
||||
self.positions.ot_es1_trz.setValue(out['ot_es1_trz']['value'])
|
||||
|
||||
# TODO move to somewhere else!
|
||||
self.calc_assistant_sideview()
|
||||
self.calc_assistant_surfaces()
|
||||
|
||||
@SafeSlot()
|
||||
def calc_bragg_angle(self, *args):
|
||||
def calc_mo1_bragg_angle(self):
|
||||
"""
|
||||
Calculates bragg angle in rad
|
||||
"""
|
||||
@@ -335,17 +357,17 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
bragg_angle_cor = (2 * cm_pitch) / np.pi * 180
|
||||
|
||||
self.input.mo1_bragg_angle.setValue(bragg_angle_cor)
|
||||
self.calc_positions()
|
||||
# self.calc_positions()
|
||||
|
||||
@SafeSlot()
|
||||
def update_mono_mode(self, *args):
|
||||
def update_mo1_mode(self):
|
||||
if self.input.mo1_mode.currentText() in 'Monochromatic':
|
||||
self.input.mo1_xtal.setDisabled(False)
|
||||
else:
|
||||
self.input.mo1_xtal.setDisabled(True)
|
||||
|
||||
@SafeSlot()
|
||||
def calc_ideal_fm_pitch(self, *args):
|
||||
def calc_fm_ideal_pitch(self):
|
||||
p = bl.fm.center[1] # posFM
|
||||
q = self.input.smpl.value() - bl.fm.center[1] # dist posFM to posEX
|
||||
f = (p * q) / (p + q) # focal length
|
||||
@@ -357,7 +379,7 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
self.input.fm_pitch_ideal.setValue(-pitch * 1e3)
|
||||
|
||||
@SafeSlot()
|
||||
def calc_crit_angle(self, *args):
|
||||
def calc_cm_crit_pitch(self):
|
||||
stripe = self.input.cm_stripe.currentText()
|
||||
# Config Mirror
|
||||
if stripe in 'Si':
|
||||
@@ -384,11 +406,11 @@ class InputPanel(QWidget):
|
||||
self._layout.setSizeConstraint(QLayout.SetFixedSize) # type: ignore
|
||||
|
||||
# Energy
|
||||
self.energy = InputNumberField('Energy [eV]', init=8979, decimals=0, single_step=100, ll=4000, hl=65000)
|
||||
self.energy = InputNumberField('energy', 'Energy [eV]', init=8979, decimals=0, single_step=100, ll=4000, hl=65000)
|
||||
|
||||
# FE Slits Acceptance
|
||||
self.sldi_hacc = InputNumberField('Horizontal [± mrad]', init=0.25, decimals=2, single_step=0.01, ll=-0.1, hl=0.9)
|
||||
self.sldi_vacc = InputNumberField('Vertical [± mrad]', init=0.1, decimals=2, single_step=0.01, ll=-0.1, hl=0.5)
|
||||
self.sldi_hacc = InputNumberField('h_acc', 'Horizontal [± mrad]', init=0.25, decimals=2, single_step=0.01, ll=-0.1, hl=0.9)
|
||||
self.sldi_vacc = InputNumberField('v_acc', 'Vertical [± mrad]', init=0.1, decimals=2, single_step=0.01, ll=-0.1, hl=0.5)
|
||||
self.sldi_ass_group = Group(
|
||||
'FE Slits Acceptance',
|
||||
[
|
||||
@@ -398,9 +420,9 @@ class InputPanel(QWidget):
|
||||
)
|
||||
|
||||
# Collimating mirror
|
||||
self.cm_stripe = ComboBox('Stripe', ['Si', 'Rh', 'Pt'])
|
||||
self.cm_stripe = ComboBox('cm_stripe', 'Stripe', ['Si', 'Rh', 'Pt'])
|
||||
self.cm_pitch_critical = NumberIndicator('Critical Pitch', 'mrad', decimals=3)
|
||||
self.cm_pitch = InputNumberField('Pitch [mrad]', init=-2.391, decimals=3, single_step=0.01, ll=-4.6, hl=-1.2)
|
||||
self.cm_pitch = InputNumberField('cm_pitch', 'Pitch [mrad]', init=-2.391, decimals=3, single_step=0.01, ll=-4.6, hl=-1.2)
|
||||
self.cm_refl = NumberIndicator('Reflectivity at x eV', '%', decimals=0)
|
||||
self.cm_refl_harm = NumberIndicator('Reflectivity at x eV', '%', decimals=0)
|
||||
self.cm_ass_group = Group(
|
||||
@@ -415,8 +437,8 @@ class InputPanel(QWidget):
|
||||
)
|
||||
|
||||
# Monochromator
|
||||
self.mo1_mode = ComboBox('Mode', ['Monochromatic', 'Pinkbeam'])
|
||||
self.mo1_xtal = ComboBox('Crystal', ['Si(111)', 'Si(311)'])
|
||||
self.mo1_mode = ComboBox('mo1_mode', 'Mode', ['Monochromatic', 'Pinkbeam'])
|
||||
self.mo1_xtal = ComboBox('mo1_xtal', 'Crystal', ['Si(111)', 'Si(311)'])
|
||||
self.mo1_bragg_angle = NumberIndicator('Bragg Angle', 'deg', decimals=1)
|
||||
self.mo1_eres = NumberIndicator('Energy Resolution', 'eV', decimals=2)
|
||||
self.mo1_ass_group = Group(
|
||||
@@ -430,9 +452,9 @@ class InputPanel(QWidget):
|
||||
)
|
||||
|
||||
# Focusing Mirror
|
||||
self.fm_stripe = ComboBox('Stripe', ['Rh (toroid)', 'Rh (flat)', 'Pt (toroid)', 'Pt (flat)'])
|
||||
self.fm_stripe = ComboBox('fm_stripe', 'Stripe', ['Rh (toroid)', 'Rh (flat)', 'Pt (toroid)', 'Pt (flat)'])
|
||||
self.fm_pitch_ideal = NumberIndicator('Ideal Pitch', 'mrad', decimals=3)
|
||||
self.fm_pitch = InputNumberField('Pitch [mrad]', init=-2.391, decimals=3, single_step=0.01, ll=-10, hl=2)
|
||||
self.fm_pitch = InputNumberField('fm_pitch', 'Pitch [mrad]', init=-2.391, decimals=3, single_step=0.01, ll=-10, hl=2)
|
||||
self.fm_refl = NumberIndicator('Reflectivity at x eV', '%', decimals=0)
|
||||
self.fm_refl_harm = NumberIndicator('Reflectivity at x eV', '%', decimals=0)
|
||||
self.fm_ass_group = Group(
|
||||
@@ -448,7 +470,7 @@ class InputPanel(QWidget):
|
||||
|
||||
# Sample
|
||||
self.cm_fm_harm_suppr = NumberIndicator('Total Suppression Factor at x eV', '', decimals=0)
|
||||
self.smpl = InputNumberField('Sample Position [mm]', init=23511, decimals=0, single_step=100, ll=23000, hl=30000)
|
||||
self.smpl = InputNumberField('smpl', 'Sample Position [mm]', init=23511, decimals=0, single_step=100, ll=23000, hl=30000)
|
||||
|
||||
# Assemble complete assitant group
|
||||
self.input_group = Group(
|
||||
@@ -597,6 +619,43 @@ class PositionsPanel(QWidget):
|
||||
self._layout .addWidget(self.position_group)
|
||||
self._layout .addStretch()
|
||||
|
||||
class MoverPanel(QWidget):
|
||||
|
||||
def __init__(self, dev, parent=None):
|
||||
super().__init__(parent)
|
||||
self.dev = dev
|
||||
self._layout = QVBoxLayout(self)
|
||||
self._layout.setSizeConstraint(QLayout.SetFixedSize) # type: ignore
|
||||
|
||||
mot = self.dev.sldi_gapx
|
||||
egu = self.dev.sldi_gapx.egu()
|
||||
prec = self.dev.sldi_gapx.precision
|
||||
self.sldi_gapx = Mover(mot, egu, prec)
|
||||
|
||||
mot = self.dev.sldi_gapy
|
||||
egu = self.dev.sldi_gapy.egu()
|
||||
prec = self.dev.sldi_gapy.precision
|
||||
self.sldi_gapy = Mover(mot, egu, prec)
|
||||
|
||||
self.sldi_mov_group = Group(
|
||||
'FE Slits',
|
||||
[
|
||||
self.sldi_gapx,
|
||||
self.sldi_gapy,
|
||||
]
|
||||
)
|
||||
|
||||
# Assemble complete assitant group
|
||||
self.mover_group = Group(
|
||||
'Mover',
|
||||
[
|
||||
self.sldi_mov_group,
|
||||
]
|
||||
)
|
||||
|
||||
self._layout .addWidget(self.mover_group)
|
||||
self._layout .addStretch()
|
||||
|
||||
class SurfacePlots(QWidget):
|
||||
"""Plot widget with two curves and legend."""
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ class Group(QGroupBox):
|
||||
# self.value.setText(text)
|
||||
|
||||
class NumberIndicator(QWidget):
|
||||
def __init__(self, label, unit=None, highlight=False, decimals=3):
|
||||
def __init__(self, label='', unit=None, highlight=False, decimals=3):
|
||||
super().__init__()
|
||||
layout = QHBoxLayout(self)
|
||||
layout.setContentsMargins(10, 0, 0, 0)
|
||||
@@ -80,44 +80,45 @@ class NumberIndicator(QWidget):
|
||||
text = text + ' ' + self.unit
|
||||
self.val.setText(text)
|
||||
|
||||
class InputTextField(QWidget):
|
||||
def __init__(self, topic, label):
|
||||
super().__init__()
|
||||
self.topic = topic
|
||||
layout = QHBoxLayout(self)
|
||||
layout.setContentsMargins(10, 0, 0, 0)
|
||||
layout.setSpacing(0)
|
||||
self.label = QLabel(label)
|
||||
self.label.setFixedWidth(140)
|
||||
self.label.setContentsMargins(0, 0, 10, 0)
|
||||
self.label.setWordWrap(True)
|
||||
layout.addWidget(self.label)
|
||||
self.val = QLineEdit()
|
||||
self.val.setPlaceholderText('0')
|
||||
# self.val.setFixedWidth(140)
|
||||
layout.addWidget(self.val)
|
||||
# class InputTextField(QWidget):
|
||||
# def __init__(self, topic, label):
|
||||
# super().__init__()
|
||||
# self.topic = topic
|
||||
# layout = QHBoxLayout(self)
|
||||
# layout.setContentsMargins(10, 0, 0, 0)
|
||||
# layout.setSpacing(0)
|
||||
# self.label = QLabel(label)
|
||||
# self.label.setFixedWidth(140)
|
||||
# self.label.setContentsMargins(0, 0, 10, 0)
|
||||
# self.label.setWordWrap(True)
|
||||
# layout.addWidget(self.label)
|
||||
# self.val = QLineEdit()
|
||||
# self.val.setPlaceholderText('0')
|
||||
# # self.val.setFixedWidth(140)
|
||||
# layout.addWidget(self.val)
|
||||
|
||||
def set_text(self, text):
|
||||
self.val.setText(text)
|
||||
# def set_text(self, text):
|
||||
# self.val.setText(text)
|
||||
|
||||
def has_focus(self) -> bool:
|
||||
return self.val.hasFocus()
|
||||
# def has_focus(self) -> bool:
|
||||
# return self.val.hasFocus()
|
||||
|
||||
def text(self) -> str:
|
||||
return self.val.text()
|
||||
# def text(self) -> str:
|
||||
# return self.val.text()
|
||||
|
||||
def set_on_return(self, func):
|
||||
"""Connect a function to the Enter/Return key press."""
|
||||
self.val.returnPressed.connect(
|
||||
partial(func, self.val, self.topic, lambda: self.val.text())
|
||||
)
|
||||
# def set_on_return(self, func):
|
||||
# """Connect a function to the Enter/Return key press."""
|
||||
# self.val.returnPressed.connect(
|
||||
# partial(func, self.val, self.topic, lambda: self.val.text())
|
||||
# )
|
||||
|
||||
class InputNumberField(QWidget):
|
||||
def __init__(self, label, init=0.0, decimals=1, single_step=0.1, ll=-1e6, hl=1e6):
|
||||
def __init__(self, identifier='', label='', init=0.0, decimals=1, single_step=0.1, ll=-1e6, hl=1e6):
|
||||
super().__init__()
|
||||
layout = QHBoxLayout(self)
|
||||
layout.setContentsMargins(10, 0, 0, 0)
|
||||
layout.setSpacing(0)
|
||||
self.identifier = identifier
|
||||
self.label = QLabel(label)
|
||||
self.label.setFixedWidth(140)
|
||||
self.label.setContentsMargins(0, 0, 10, 0)
|
||||
@@ -143,74 +144,16 @@ class InputNumberField(QWidget):
|
||||
def value_changed_connect(self, func):
|
||||
"""Connect a function to the Enter/Return key press."""
|
||||
self.val.valueChanged.connect(
|
||||
partial(func, self.val, lambda: self.val.value())
|
||||
partial(func, identifier=self.identifier, value_obj=self.val, value=lambda: self.val.value())
|
||||
)
|
||||
|
||||
# class IPAdressInputField(QWidget):
|
||||
# def __init__(self, topic, label):
|
||||
# super().__init__()
|
||||
# self.topic = topic
|
||||
# layout = QHBoxLayout(self)
|
||||
# layout.setContentsMargins(10, 0, 0, 0)
|
||||
# layout.setSpacing(0)
|
||||
# self.label = QLabel(label)
|
||||
# self.label.setFixedWidth(150)
|
||||
# layout.addWidget(self.label)
|
||||
# self.oct0 = QLineEdit()
|
||||
# self.oct0.setPlaceholderText('0')
|
||||
# self.oct0.setFixedWidth(30)
|
||||
# layout.addWidget(self.oct0)
|
||||
# separator1 = QLabel('.')
|
||||
# layout.addWidget(separator1)
|
||||
# self.oct1 = QLineEdit()
|
||||
# self.oct1.setPlaceholderText('0')
|
||||
# self.oct1.setFixedWidth(30)
|
||||
# layout.addWidget(self.oct1)
|
||||
# separator2 = QLabel('.')
|
||||
# layout.addWidget(separator2)
|
||||
# self.oct2 = QLineEdit()
|
||||
# self.oct2.setPlaceholderText('0')
|
||||
# self.oct2.setFixedWidth(30)
|
||||
# layout.addWidget(self.oct2)
|
||||
# separator3 = QLabel('.')
|
||||
# layout.addWidget(separator3)
|
||||
# self.oct3 = QLineEdit()
|
||||
# self.oct3.setPlaceholderText('0')
|
||||
# self.oct3.setFixedWidth(30)
|
||||
# layout.addWidget(self.oct3)
|
||||
|
||||
# self.oct0.editingFinished.connect(partial(self.check_octet, self.oct0))
|
||||
# self.oct1.editingFinished.connect(partial(self.check_octet, self.oct1))
|
||||
# self.oct2.editingFinished.connect(partial(self.check_octet, self.oct2))
|
||||
# self.oct3.editingFinished.connect(partial(self.check_octet, self.oct3))
|
||||
|
||||
# def check_octet(self, octet):
|
||||
# if octet.text().isnumeric():
|
||||
# if int(octet.text()) < 0:
|
||||
# octet.setText('0')
|
||||
# if int(octet.text()) > 254:
|
||||
# octet.setText('254')
|
||||
# else:
|
||||
# octet.setText('')
|
||||
|
||||
# def get_ip(self):
|
||||
# return f'{self.oct0.text()}.{self.oct1.text()}.{self.oct2.text()}.{self.oct3.text()}'
|
||||
|
||||
# def set_ip(self, ip):
|
||||
# octets = ip.split('.')
|
||||
# if len(octets) == 4 and all(octet.isnumeric() for octet in octets):
|
||||
# if all(int(octet) > 0 and int(octet) < 254 for octet in octets):
|
||||
# self.oct0.setText(octets[0])
|
||||
# self.oct1.setText(octets[1])
|
||||
# self.oct2.setText(octets[2])
|
||||
# self.oct3.setText(octets[3])
|
||||
|
||||
class ComboBox(QWidget):
|
||||
def __init__(self, label, enums):
|
||||
def __init__(self, identifier='', label='', enums=[]):
|
||||
super().__init__()
|
||||
layout = QHBoxLayout(self)
|
||||
layout.setContentsMargins(10, 0, 0, 0)
|
||||
layout.setSpacing(0)
|
||||
self.identifier = identifier
|
||||
self.label = QLabel(label)
|
||||
self.label.setFixedWidth(140)
|
||||
self.label.setContentsMargins(0, 0, 10, 0)
|
||||
@@ -233,72 +176,76 @@ class ComboBox(QWidget):
|
||||
def activated_connect(self, func):
|
||||
"""Connect a function to the Enter/Return key press."""
|
||||
self.value.activated.connect(
|
||||
partial(func, self.value, lambda: self.value.currentText())
|
||||
partial(func, identifier=self.identifier, value_obj=self.value, value=lambda: self.value.currentText())
|
||||
)
|
||||
|
||||
def setDisabled(self, disable):
|
||||
self.value.setDisabled(disable)
|
||||
|
||||
# class LED(QWidget):
|
||||
# def __init__(self, states, colors, label):
|
||||
# super().__init__()
|
||||
# self.states = states
|
||||
# self.colors = colors
|
||||
# layout = QHBoxLayout(self)
|
||||
# layout.setContentsMargins(10, 0, 0, 0)
|
||||
# layout.setSpacing(0)
|
||||
# self.label = QLabel(label)
|
||||
# self.label.setFixedWidth(150)
|
||||
# layout.addWidget(self.label)
|
||||
# self.led = QLabel()
|
||||
# self.led.setFixedWidth(160)
|
||||
# layout.addWidget(self.led)
|
||||
class Mover(QWidget):
|
||||
def __init__(self, dev, egu, prec):
|
||||
super().__init__()
|
||||
layout = QHBoxLayout(self)
|
||||
layout.setContentsMargins(10, 0, 0, 0)
|
||||
layout.setSpacing(0)
|
||||
self.position = QLabel('-')
|
||||
self.position.setFixedWidth(150)
|
||||
layout.addWidget(self.position)
|
||||
self.led = QLabel()
|
||||
self.led.setFixedWidth(30)
|
||||
self.led.setStyleSheet("background-color: 0, 0, 0; border: 1px solid black;")
|
||||
layout.addWidget(self.led)
|
||||
self.start = QPushButton('Move')
|
||||
self.start.setStyleSheet("color: black; background-color: green;")
|
||||
self.start.setFixedWidth(80)
|
||||
self.stop = QPushButton('Stop')
|
||||
self.stop.setStyleSheet("color: black; background-color: firebrick;")
|
||||
self.stop.setFixedWidth(80)
|
||||
layout.addWidget(self.start)
|
||||
layout.addWidget(self.stop)
|
||||
self.dev = dev
|
||||
self.unit = egu
|
||||
self.decimals = prec
|
||||
|
||||
# def apply_color(self, val):
|
||||
# color = self.colors[self.states.index(val)]
|
||||
# self.led.setStyleSheet(f"background-color: {color}; border: 1px solid black;")
|
||||
def led_set_status(self, status):
|
||||
if status in 'out':
|
||||
self.led.setStyleSheet("background-color: 255, 0, 0; border: 1px solid black;")
|
||||
elif status in 'moving':
|
||||
self.led.setStyleSheet("background-color: 255, 255, 0; border: 1px solid black;")
|
||||
elif status in 'in':
|
||||
self.led.setStyleSheet("background-color: 0, 255, 0; border: 1px solid black;")
|
||||
|
||||
# class StartStop(QWidget):
|
||||
# def __init__(self, label, label_buttons=['Start', 'Stop']):
|
||||
# super().__init__()
|
||||
# layout = QHBoxLayout(self)
|
||||
# layout.setContentsMargins(10, 0, 0, 0)
|
||||
# layout.setSpacing(0)
|
||||
# self.label = QLabel(label)
|
||||
# self.label.setFixedWidth(150)
|
||||
# layout.addWidget(self.label)
|
||||
# self.start = QPushButton(label_buttons[0])
|
||||
# self.start.setStyleSheet("color: black; background-color: green;")
|
||||
# self.start.setFixedWidth(80)
|
||||
# self.stop = QPushButton(label_buttons[1])
|
||||
# self.stop.setStyleSheet("color: black; background-color: firebrick;")
|
||||
# self.stop.setFixedWidth(80)
|
||||
# layout.addWidget(self.start)
|
||||
# layout.addWidget(self.stop)
|
||||
def position_setValue(self, number):
|
||||
text = f'{number:.{int(self.decimals)}f}'
|
||||
if self.unit is not None:
|
||||
text = text + ' ' + self.unit
|
||||
self.position.setText(text)
|
||||
|
||||
# def set_on_start(self, func):
|
||||
# """Connect a function to the start button press."""
|
||||
# self.start.clicked.connect(func)
|
||||
def start_clicked_connect(self, func):
|
||||
"""Connect a function to the start button press."""
|
||||
self.start.clicked.connect(
|
||||
partial(func, dev=self.dev)
|
||||
)
|
||||
|
||||
# def set_on_stop(self, func):
|
||||
# """Connect a function to the stop button press."""
|
||||
# self.stop.clicked.connect(func)
|
||||
def stop_clicked_connect(self, func):
|
||||
"""Connect a function to the stop button press."""
|
||||
self.stop.clicked.connect(
|
||||
partial(func, dev=self.dev)
|
||||
)
|
||||
|
||||
# def enable_start(self):
|
||||
# self.start.setEnabled(True)
|
||||
# self.start.setStyleSheet("color: black; background-color: green;")
|
||||
def start_setEnabled(self, enable):
|
||||
self.start.setEnabled(enable)
|
||||
if enable:
|
||||
self.start.setStyleSheet("color: black; background-color: green;")
|
||||
else:
|
||||
self.start.setStyleSheet("color: black; background-color: grey;")
|
||||
|
||||
# def enable_stop(self):
|
||||
# self.stop.setEnabled(True)
|
||||
# self.stop.setStyleSheet("color: black; background-color: firebrick;")
|
||||
|
||||
# def disable_start(self):
|
||||
# self.start.setEnabled(False)
|
||||
# self.start.setStyleSheet("color: black; background-color: grey;")
|
||||
|
||||
# def disable_stop(self):
|
||||
# self.stop.setEnabled(False)
|
||||
# self.stop.setStyleSheet("color: black; background-color: grey;")
|
||||
def stop_setEnabled(self, enable):
|
||||
self.stop.setEnabled(enable)
|
||||
if enable:
|
||||
self.stop.setStyleSheet("color: black; background-color: firebrick;")
|
||||
else:
|
||||
self.stop.setStyleSheet("color: black; background-color: grey;")
|
||||
|
||||
# class Button(QWidget):
|
||||
# def __init__(self, label, label_button):
|
||||
@@ -328,3 +275,22 @@ class ComboBox(QWidget):
|
||||
|
||||
# def set_button_text(self, text):
|
||||
# self.button.setText(text)
|
||||
|
||||
# class LED(QWidget):
|
||||
# def __init__(self, states, colors, label):
|
||||
# super().__init__()
|
||||
# self.states = states
|
||||
# self.colors = colors
|
||||
# layout = QHBoxLayout(self)
|
||||
# layout.setContentsMargins(10, 0, 0, 0)
|
||||
# layout.setSpacing(0)
|
||||
# self.label = QLabel(label)
|
||||
# self.label.setFixedWidth(150)
|
||||
# layout.addWidget(self.label)
|
||||
# self.led = QLabel()
|
||||
# self.led.setFixedWidth(160)
|
||||
# layout.addWidget(self.led)
|
||||
|
||||
# def apply_color(self, val):
|
||||
# color = self.colors[self.states.index(val)]
|
||||
# self.led.setStyleSheet(f"background-color: {color}; border: 1px solid black;")
|
||||
Reference in New Issue
Block a user