wip: digital twin
This commit is contained in:
@@ -7,7 +7,7 @@ import debye_bec.bec_widgets.widgets.digital_twin.x01da_parameters as bl
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
def calculate_positions(cfg):
|
||||
def calc_positions(cfg):
|
||||
|
||||
pos = {}
|
||||
|
||||
@@ -56,7 +56,7 @@ def calculate_positions(cfg):
|
||||
# See raytracing script or here: bragg = np.asin(rm.ch / (2.*cfg['dSpacing']*cfg['energyCCM'])) - aCrystal.get_dtheta_symmetric_Bragg(cfg['energyCCM'])
|
||||
if cfg['mo_mode'] == 'Monochromatic':
|
||||
# Add 2x CM pitch to the bragg angle
|
||||
bragg = ((2 * cfg['cm_pitch']) + cfg['mo_bragg'][1]) / np.pi * 180
|
||||
bragg = ((2 * cfg['cm_pitch']) + cfg['mo_bragg']) / np.pi * 180
|
||||
elif cfg['mo_mode'] == 'Pinkbeam':
|
||||
# Align xtal surfaces parallel to beam
|
||||
bragg = (2 * cfg['cm_pitch']) / np.pi * 180
|
||||
@@ -65,12 +65,12 @@ def calculate_positions(cfg):
|
||||
pos['mo1_bragg_angle'] = {'value': bragg} # Bragg angle in deg
|
||||
|
||||
# TRY, Height
|
||||
l = bl.mo1.xtalGap[0]/np.sin(cfg['mo_bragg'][1])
|
||||
yhor = l*np.cos(2.*(cfg['mo_bragg'][1]+cfg['cm_pitch']))
|
||||
l = bl.mo1.xtalGap[0]/np.sin(cfg['mo_bragg'])
|
||||
yhor = l*np.cos(2.*(cfg['mo_bragg']+cfg['cm_pitch']))
|
||||
yver = yhor*np.tan(2.*cfg['cm_pitch'])
|
||||
|
||||
if cfg['mo_mode'] == 'Monochromatic':
|
||||
beamOffsetCCM = l*np.sin(2.*(cfg['mo_bragg'][1]+cfg['cm_pitch']))-yver # Resultat ist korrekt!
|
||||
beamOffsetCCM = l*np.sin(2.*(cfg['mo_bragg']+cfg['cm_pitch']))-yver # Resultat ist korrekt!
|
||||
elif cfg['mo_mode'] == 'Pinkbeam':
|
||||
beamOffsetCCM = 0
|
||||
else:
|
||||
@@ -84,22 +84,22 @@ def calculate_positions(cfg):
|
||||
|
||||
# calculate height of center of first crystal surface
|
||||
f = bl.mo1.rotOffset # rotation offset, mm
|
||||
logger.info(f'f = {f}')
|
||||
# logger.info(f'f = {f}')
|
||||
d = bl.mo1.heightOffset # xtal height offset, mm
|
||||
logger.info(f'd = {d}')
|
||||
c = d*csc(cfg['mo_bragg'][1])-f*cot(cfg['mo_bragg'][1])
|
||||
logger.info(f'c = {c}')
|
||||
# logger.info(f'd = {d}')
|
||||
c = d*csc(cfg['mo_bragg'])-f*cot(cfg['mo_bragg'])
|
||||
# logger.info(f'c = {c}')
|
||||
|
||||
# Calculate height of center of rotation
|
||||
b = np.sqrt(d**2*csc(cfg['mo_bragg'][1])**2-2*d*f*cot(cfg['mo_bragg'][1])*csc(cfg['mo_bragg'][1])+f**2*cot(cfg['mo_bragg'][1])**2+f**2)
|
||||
logger.info(f'b = {b}')
|
||||
h = np.cos(np.pi/2-np.arctan(f/c)-cfg['mo_bragg'][1]-2*cfg['cm_pitch'])*b
|
||||
logger.info(f'h = {h}')
|
||||
b = np.sqrt(d**2*csc(cfg['mo_bragg'])**2-2*d*f*cot(cfg['mo_bragg'])*csc(cfg['mo_bragg'])+f**2*cot(cfg['mo_bragg'])**2+f**2)
|
||||
# logger.info(f'b = {b}')
|
||||
h = np.cos(np.pi/2-np.arctan(f/c)-cfg['mo_bragg']-2*cfg['cm_pitch'])*b
|
||||
# logger.info(f'h = {h}')
|
||||
h2 = ((bl.mo1.center[1] - bl.cm.center[1])-np.sqrt(b**2-h**2))*np.tan(2*cfg['cm_pitch'])
|
||||
logger.info(f'mo1 = {bl.mo1.center[1]}')
|
||||
logger.info(f'cm = {bl.cm.center[1]}')
|
||||
logger.info(f'pitch = {cfg["cm_pitch"]}')
|
||||
logger.info(f'h2 = {h2}')
|
||||
# logger.info(f'mo1 = {bl.mo1.center[1]}')
|
||||
# logger.info(f'cm = {bl.cm.center[1]}')
|
||||
# logger.info(f'pitch = {cfg["cm_pitch"]}')
|
||||
# logger.info(f'h2 = {h2}')
|
||||
#TODO Mono height not exactly the same as in raytracing
|
||||
heightCCM1real = h + h2 # per design, the height should not change if the pitch of the CM is not changed!
|
||||
# heightCCM1real = heightCCM1real - 30 # Zero position of stage is at 1430 mm from ground.
|
||||
@@ -112,12 +112,15 @@ def calculate_positions(cfg):
|
||||
pos['mo1_try'] = {'value': heightCCM1real}
|
||||
|
||||
# TRX, Crystal selection
|
||||
try:
|
||||
xtal = cfg['mo_xtal'].translate(str.maketrans('', '', '()')) # Remove brackets from xtal name to conform with parameters
|
||||
index = bl.mo1.xtal.index(xtal)
|
||||
except:
|
||||
raise ValueError(f"Requested xtal {xtal} not found in parameters!")
|
||||
pos['mo1_trx'] = {'value': bl.mo1.xtalOffsetX[index]}
|
||||
if cfg['mo_mode'] == 'Monochromatic':
|
||||
try:
|
||||
xtal = cfg['mo_xtal'].translate(str.maketrans('', '', '()')) # Remove brackets from xtal name to conform with parameters
|
||||
index = bl.mo1.xtal.index(xtal)
|
||||
except:
|
||||
raise ValueError(f"Requested xtal {xtal} not found in parameters!")
|
||||
pos['mo1_trx'] = {'value': bl.mo1.xtalOffsetX[index]}
|
||||
else:
|
||||
pos['mo1_trx'] = {'value': 0}
|
||||
|
||||
|
||||
#TODO move to mono, calc for beam Z-movement between crystal surfaces
|
||||
@@ -131,9 +134,9 @@ def calculate_positions(cfg):
|
||||
|
||||
## Beam Monitor 1
|
||||
d = bl.opBM1.center[1] - bl.cm.center[1] - dz
|
||||
logger.info(f'distance: {d}')
|
||||
logger.info(f'cm pitch: {cfg["cm_pitch"]}')
|
||||
logger.info(f'mono offset: {beamOffsetCCM}')
|
||||
# logger.info(f'distance: {d}')
|
||||
# logger.info(f'cm pitch: {cfg["cm_pitch"]}')
|
||||
# logger.info(f'mono offset: {beamOffsetCCM}')
|
||||
bm1_beam_height = d * np.tan(2 * cfg['cm_pitch']) + beamOffsetCCM
|
||||
pos['bm1_try'] = {'value': bm1_beam_height}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import sys
|
||||
import os
|
||||
import datetime
|
||||
import numpy as np
|
||||
from bec_lib import bec_logger
|
||||
@@ -17,7 +18,10 @@ 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.digital_twin.calculate_positions import calculate_positions
|
||||
from debye_bec.bec_widgets.widgets.digital_twin.calculate_positions import calc_positions
|
||||
|
||||
from xrt.backends.raycing.physconsts import CHeVcm, AVOGADRO
|
||||
import debye_bec.bec_widgets.widgets.digital_twin.x01da_parameters as bl
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
@@ -45,32 +49,44 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
|
||||
self.plot_widget = PlotWidget(title='Plot title', chart_data = [])
|
||||
self.input = InputPanel()
|
||||
self.positions_panel = PositionsPanel()
|
||||
self.positions = PositionsPanel()
|
||||
|
||||
self.root_layout.addWidget(self.plot_widget, stretch=3)
|
||||
self.root_layout.addWidget(self.input, stretch=1, alignment=Qt.AlignTop)
|
||||
self.root_layout.addWidget(self.positions_panel, stretch=1, alignment=Qt.AlignTop)
|
||||
self.root_layout.addWidget(self.positions, stretch=1, alignment=Qt.AlignTop)
|
||||
|
||||
self.setLayout(self.root_layout)
|
||||
self.setWindowTitle("Digital Twin")
|
||||
self.resize(600, 500)
|
||||
|
||||
self.input.energy.value_changed_connect(self.calculate_positions)
|
||||
self.input.sldi_hacc.value_changed_connect(self.calculate_positions)
|
||||
self.input.sldi_vacc.value_changed_connect(self.calculate_positions)
|
||||
self.input.cm_stripe.activated_connect(self.calculate_positions)
|
||||
self.input.cm_pitch.value_changed_connect(self.calculate_positions)
|
||||
self.input.mo1_mode.activated_connect(self.calculate_positions)
|
||||
self.input.mo1_xtal.activated_connect(self.calculate_positions)
|
||||
self.input.fm_stripe.activated_connect(self.calculate_positions)
|
||||
self.input.fm_pitch.value_changed_connect(self.calculate_positions)
|
||||
self.input.smpl.value_changed_connect(self.calculate_positions)
|
||||
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.bragg_angle = 0
|
||||
self.calc_bragg_angle()
|
||||
self.calc_ideal_fm_pitch()
|
||||
self.calc_crit_angle()
|
||||
|
||||
@SafeSlot()
|
||||
def calculate_positions(self, field, qt_obj, number, *args):
|
||||
logger.info(f'Got field {field} and number {qt_obj} and number {number} and args {args}')
|
||||
def calc_positions(self, *args):
|
||||
# logger.info(f'Got field {field} and number {qt_obj} and number {number} and args {args}')
|
||||
|
||||
config = { # Config in SI units!
|
||||
'energy' : self.input.energy.value(),
|
||||
@@ -80,7 +96,7 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
'cm_stripe' : self.input.cm_stripe.currentText(),
|
||||
'mo_mode' : self.input.mo1_mode.currentText(),
|
||||
'mo_xtal' : self.input.mo1_xtal.currentText(),
|
||||
'mo_bragg' : [12.725, 12.725],
|
||||
'mo_bragg' : self.bragg_angle,
|
||||
'fm_pitch' : -self.input.fm_pitch.value() * 1e-3,
|
||||
'fm_stripe' : self.input.fm_stripe.currentText(),
|
||||
'fm_gain_height' : 1,
|
||||
@@ -88,10 +104,53 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
}
|
||||
|
||||
logger.info(f'Config created: {config}')
|
||||
out = calc_positions(config)
|
||||
logger.info(f'Got positions: {out}')
|
||||
|
||||
positions = calculate_positions(config)
|
||||
self.positions.sldi_gapx.setValue(out['sldi_gapx']['value'])
|
||||
self.positions.sldi_gapy.setValue(out['sldi_gapy']['value'])
|
||||
self.positions.cm_trx.setValue(out['cm_trx']['value'])
|
||||
self.positions.cm_try.setValue(out['cm_try']['value'])
|
||||
self.positions.cm_bnd.setValue(out['cm_bnd_radius']['value'])
|
||||
self.positions.cm_rotx.setValue(out['cm_rotx']['value'])
|
||||
self.positions.mo1_bragg_angle.setValue(out['mo1_bragg_angle']['value'])
|
||||
self.positions.mo1_trx.setValue(out['mo1_trx']['value'])
|
||||
self.positions.mo1_try.setValue(out['mo1_try']['value'])
|
||||
self.positions.sl1_centery.setValue(out['sl1_centery']['value'])
|
||||
self.positions.bm1_try.setValue(out['bm1_try']['value'])
|
||||
self.positions.fm_trx.setValue(out['fm_trx']['value'])
|
||||
self.positions.fm_try.setValue(out['fm_try']['value'])
|
||||
self.positions.fm_bnd.setValue(out['fm_bnd_radius']['value'])
|
||||
self.positions.fm_rotx.setValue(out['fm_rotx']['value'])
|
||||
self.positions.sl2_centery.setValue(out['sl2_centery']['value'])
|
||||
self.positions.bm2_try.setValue(out['bm2_try']['value'])
|
||||
self.positions.ot_try.setValue(out['ot_try']['value'])
|
||||
self.positions.ot_rotx.setValue(out['ot_rotx']['value'])
|
||||
self.positions.ot_es1_trz.setValue(out['ot_es1_trz']['value'])
|
||||
|
||||
logger.info(f'Got positions: {positions}')
|
||||
@SafeSlot()
|
||||
def calc_bragg_angle(self, *args):
|
||||
"""
|
||||
Calculates bragg angle in rad
|
||||
"""
|
||||
xtal = self.input.mo1_xtal.currentText()
|
||||
if xtal in 'Si(111)':
|
||||
d_spacing = self.dev.mo1_bragg.crystal.d_spacing_si111.get()
|
||||
elif xtal in 'Si(311)':
|
||||
d_spacing = self.dev.mo1_bragg.crystal.d_spacing_si311.get()
|
||||
else:
|
||||
raise Exception(f'Invalid xtal selection: {xtal}')
|
||||
|
||||
H = 6.62606957E-34
|
||||
E = 1.602176634E-19
|
||||
C = 299792458
|
||||
|
||||
wl = C * H / (E * self.input.energy.value())
|
||||
val = wl / (2 * d_spacing * 1e-10)
|
||||
self.bragg_angle = 0
|
||||
if val > -1 and val < 1:
|
||||
self.bragg_angle = np.asin(val)
|
||||
self.calc_positions()
|
||||
|
||||
@SafeSlot()
|
||||
def update_mono_mode(self, *args):
|
||||
@@ -101,141 +160,36 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
else:
|
||||
self.input.mo1_xtal.setDisabled(True)
|
||||
|
||||
# self.init_ui()
|
||||
# self._recalculate() # populate outputs on startup
|
||||
|
||||
# Timer: update plot every 1 second
|
||||
# self._timer = QTimer(self)
|
||||
# self._timer.setInterval(1000)
|
||||
# self._timer.timeout.connect(self._tick)
|
||||
# self._timer.start()
|
||||
|
||||
# ------------------------------------------------------------------ UI ---
|
||||
|
||||
# def init_ui(self):
|
||||
|
||||
# self.spin_a = InputNumberField('Acceptance 1')
|
||||
# self.spin_b = InputNumberField('Acceptance 2')
|
||||
# self.input_group = Group(
|
||||
# 'Inputs',
|
||||
# [
|
||||
# self.spin_a,
|
||||
# self.spin_b,
|
||||
# ]
|
||||
# )
|
||||
# self.root_layout.addWidget(self.input_group)
|
||||
# self.root_layout.addStretch()
|
||||
|
||||
|
||||
# root = QVBoxLayout(self)
|
||||
|
||||
# # --- Inputs ---
|
||||
# input_group = QGroupBox("Inputs")
|
||||
# input_layout = QHBoxLayout(input_group)
|
||||
|
||||
# self._spin_a = QLineEdit()
|
||||
# self._spin_a.setPlaceholderText('0')
|
||||
# self._spin_a.setText('0')
|
||||
# # self._spin_a.setRange(-1e6, 1e6)
|
||||
# # self._spin_a.setDecimals(3)
|
||||
# # self._spin_a.setValue(1.0)
|
||||
# # self._spin_a.setSingleStep(0.1)
|
||||
|
||||
# self._spin_b = QLineEdit()
|
||||
# self._spin_b.setPlaceholderText('0')
|
||||
# self._spin_b.setText('0')
|
||||
# # self._spin_b.setRange(-1e6, 1e6)
|
||||
# # self._spin_b.setDecimals(3)
|
||||
# # self._spin_b.setValue(2.0)
|
||||
# # self._spin_b.setSingleStep(0.1)
|
||||
|
||||
# self._spin_c = QLineEdit()
|
||||
# self._spin_c.setPlaceholderText('0')
|
||||
# self._spin_c.setText('10')
|
||||
|
||||
# input_layout.addWidget(QLabel("A:"))
|
||||
# input_layout.addWidget(self._spin_a)
|
||||
# input_layout.addWidget(QLabel("B:"))
|
||||
# input_layout.addWidget(self._spin_b)
|
||||
# input_layout.addWidget(QLabel("C:"))
|
||||
# input_layout.addWidget(self._spin_c)
|
||||
# root.addWidget(input_group)
|
||||
|
||||
# # --- Outputs ---
|
||||
# output_group = QGroupBox("Outputs")
|
||||
# output_layout = QHBoxLayout(output_group)
|
||||
|
||||
# self._label_sum = QLabel("Sum: —")
|
||||
# self._label_product = QLabel("Product: —")
|
||||
# output_layout.addWidget(self._label_sum)
|
||||
# output_layout.addWidget(self._label_product)
|
||||
# root.addWidget(output_group)
|
||||
|
||||
# # --- Plot ---
|
||||
# plot_group = QGroupBox("Live History (updates every 1 s)")
|
||||
# plot_layout = QVBoxLayout(plot_group)
|
||||
|
||||
# self._plot_widget = pg.PlotWidget()
|
||||
# self._plot_widget.setBackground("w")
|
||||
# self._plot_widget.addLegend()
|
||||
# self._plot_widget.setLabel("left", "Value")
|
||||
# self._plot_widget.setLabel("bottom", "Tick")
|
||||
|
||||
# self._curve_sum = self._plot_widget.plot(
|
||||
# pen=pg.mkPen("b", width=2), name="Sum"
|
||||
# )
|
||||
# self._curve_product = self._plot_widget.plot(
|
||||
# pen=pg.mkPen("r", width=2), name="Product"
|
||||
# )
|
||||
# plot_layout.addWidget(self._plot_widget)
|
||||
# plot_group.setLayout(plot_layout)
|
||||
# root.addWidget(plot_group)
|
||||
|
||||
# self.setLayout(root)
|
||||
# self.setWindowTitle("BEC Calculator Widget")
|
||||
# self.resize(600, 500)
|
||||
|
||||
# # Connect inputs → recalculate
|
||||
# self._spin_a.editingFinished .connect(self._recalculate)
|
||||
# self._spin_b.editingFinished .connect(self._recalculate)
|
||||
|
||||
# ---------------------------------------------------------- Logic ---
|
||||
|
||||
# @SafeSlot()
|
||||
# def _recalculate(self):
|
||||
# # logger.info(var)
|
||||
# a = float(self._spin_a.text())
|
||||
# b = float(self._spin_b.text())
|
||||
# s = a + b
|
||||
# p = a * b
|
||||
# self._label_sum.setText(f"Sum: {s:.4f}")
|
||||
# self._label_product.setText(f"Product: {p:.4f}")
|
||||
# self._current_sum = s
|
||||
# self._current_product = p
|
||||
|
||||
# @SafeSlot()
|
||||
# def _tick(self):
|
||||
# """Called every second: record current outputs and refresh plot."""
|
||||
# self._history.append((self._t, self._current_sum, self._current_product))
|
||||
# self._t += 1
|
||||
|
||||
# ticks = [h[0] for h in self._history]
|
||||
# sums = [h[1] for h in self._history]
|
||||
# products = [h[2] for h in self._history]
|
||||
|
||||
# self._curve_sum.setData(ticks, sums)
|
||||
# self._curve_product.setData(ticks, products)
|
||||
|
||||
# # --------------------------------------------------- RPC interface ---
|
||||
|
||||
# def set_a(self, value: float):
|
||||
# """Set input A remotely from the BEC CLI."""
|
||||
# self._spin_a.setValue(value)
|
||||
|
||||
# def set_b(self, value: float):
|
||||
# """Set input B remotely from the BEC CLI."""
|
||||
# self._spin_b.setValue(value)
|
||||
@SafeSlot()
|
||||
def calc_ideal_fm_pitch(self, *args):
|
||||
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
|
||||
pitch = 0
|
||||
if 'Rh' in self.input.fm_stripe.currentText():
|
||||
pitch = np.arcsin(bl.fm.r[0]/(2*f))# ideal pitch for FM
|
||||
if 'Pt' in self.input.fm_stripe.currentText():
|
||||
pitch = np.arcsin(bl.fm.r[1]/(2*f)) # ideal pitch for FM
|
||||
self.input.fm_pitch_ideal.setValue(-pitch * 1e3)
|
||||
|
||||
@SafeSlot()
|
||||
def calc_crit_angle(self, *args):
|
||||
stripe = self.input.cm_stripe.currentText()
|
||||
# Config Mirror
|
||||
if stripe in 'Si':
|
||||
stripe = bl.stripeSi
|
||||
elif stripe in 'Pt':
|
||||
stripe = bl.stripePt
|
||||
elif stripe in 'Rh':
|
||||
stripe = bl.stripeRh
|
||||
else:
|
||||
raise Exception(f'Stripe {stripe} not found in beamline parameters!')
|
||||
w = CHeVcm/100/self.input.energy.value() # convert energy [eV] to wavelength [m]
|
||||
# Calculate critical angle for mirror
|
||||
f1 = stripe.elements[0].Z + np.real(stripe.elements[0].get_f1f2(self.input.energy.value()))
|
||||
numberDensity = stripe.rho*1e3*AVOGADRO/(stripe.elements[0].mass/1e3)
|
||||
criticalAngle = np.sqrt(numberDensity*2.8179e-15*w**2*f1/np.pi)
|
||||
self.input.cm_pitch_critical.setValue(-criticalAngle * 1e3)
|
||||
|
||||
class InputPanel(QWidget):
|
||||
"""Right-side control panel: input field, indicator, send, recording."""
|
||||
@@ -262,7 +216,7 @@ class InputPanel(QWidget):
|
||||
# Collimating mirror
|
||||
self.cm_stripe = ComboBox('Stripe', ['Si', 'Rh', 'Pt'])
|
||||
self.cm_pitch_critical = NumberIndicator('Critical Pitch', 'mrad', decimals=3)
|
||||
self.cm_pitch = InputNumberField('Pitch [mrad]', init=-3, decimals=3, single_step=0.01, ll=-4.6, hl=-1.2)
|
||||
self.cm_pitch = InputNumberField('Pitch [mrad]', init=-2.391, decimals=3, single_step=0.01, ll=-4.6, hl=-1.2)
|
||||
self.cm_ass_group = Group(
|
||||
'Collimating Mirror',
|
||||
[
|
||||
@@ -286,7 +240,7 @@ class InputPanel(QWidget):
|
||||
# Focusing Mirror
|
||||
self.fm_stripe = ComboBox('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=-3, decimals=3, single_step=0.01, ll=-10, hl=2)
|
||||
self.fm_pitch = InputNumberField('Pitch [mrad]', init=-2.391, decimals=3, single_step=0.01, ll=-10, hl=2)
|
||||
self.fm_ass_group = Group(
|
||||
'Focusing Mirror',
|
||||
[
|
||||
@@ -297,7 +251,7 @@ class InputPanel(QWidget):
|
||||
)
|
||||
|
||||
# Sample
|
||||
self.smpl = InputNumberField('Sample Position [mm]')
|
||||
self.smpl = InputNumberField('Sample Position [mm]', init=23511, decimals=0, single_step=100, ll=23000, hl=30000)
|
||||
|
||||
# Assemble complete assitant group
|
||||
self.input_group = Group(
|
||||
@@ -337,8 +291,8 @@ class PositionsPanel(QWidget):
|
||||
# Collimating mirror
|
||||
self.cm_trx = NumberIndicator('TRX', 'mm', decimals=1)
|
||||
self.cm_try = NumberIndicator('TRY', 'mm', decimals=3)
|
||||
self.cm_bnd = NumberIndicator('BENDER', 'mm', decimals=2)
|
||||
self.cm_rotx = NumberIndicator('PITCH', 'mm', decimals=3)
|
||||
self.cm_bnd = NumberIndicator('BENDER', 'km', decimals=2)
|
||||
self.cm_rotx = NumberIndicator('PITCH', 'mrad', decimals=3)
|
||||
self.cm_pos_group = Group(
|
||||
'Collimating Mirror',
|
||||
[
|
||||
@@ -350,7 +304,7 @@ class PositionsPanel(QWidget):
|
||||
)
|
||||
|
||||
# Monochromator
|
||||
self.mo1_bragg_angle = NumberIndicator('Bragg Angle', 'mm', decimals=3)
|
||||
self.mo1_bragg_angle = NumberIndicator('Bragg Angle', 'deg', decimals=3)
|
||||
self.mo1_trx = NumberIndicator('TRX', 'mm', decimals=1)
|
||||
self.mo1_try = NumberIndicator('TRY', 'mm', decimals=3)
|
||||
self.mo1_pos_group = Group(
|
||||
@@ -383,8 +337,8 @@ class PositionsPanel(QWidget):
|
||||
# Focusing Mirror
|
||||
self.fm_trx = NumberIndicator('TRX', 'mm', decimals=1)
|
||||
self.fm_try = NumberIndicator('TRY', 'mm', decimals=3)
|
||||
self.fm_bnd = NumberIndicator('BENDER', 'mm', decimals=2)
|
||||
self.fm_rotx = NumberIndicator('PITCH', 'mm', decimals=3)
|
||||
self.fm_bnd = NumberIndicator('BENDER', 'km', decimals=2)
|
||||
self.fm_rotx = NumberIndicator('PITCH', 'mrad', decimals=3)
|
||||
self.fm_pos_group = Group(
|
||||
'Focusing Mirror',
|
||||
[
|
||||
@@ -414,15 +368,15 @@ class PositionsPanel(QWidget):
|
||||
)
|
||||
|
||||
# Optical Table
|
||||
self.es_try = NumberIndicator('TRY', 'mm', decimals=3)
|
||||
self.es_rotx = NumberIndicator('ROTX', 'mm', decimals=3)
|
||||
self.es1_trz = NumberIndicator('ES1 TRZ', 'mm', decimals=0)
|
||||
self.es_pos_group = Group(
|
||||
self.ot_try = NumberIndicator('TRY', 'mm', decimals=0)
|
||||
self.ot_rotx = NumberIndicator('ROTX', 'mrad', decimals=3)
|
||||
self.ot_es1_trz = NumberIndicator('ES1 TRZ', 'mm', decimals=0)
|
||||
self.ot_pos_group = Group(
|
||||
'Optical Table',
|
||||
[
|
||||
self.es_try,
|
||||
self.es_rotx,
|
||||
self.es1_trz,
|
||||
self.ot_try,
|
||||
self.ot_rotx,
|
||||
self.ot_es1_trz,
|
||||
]
|
||||
)
|
||||
|
||||
@@ -438,7 +392,7 @@ class PositionsPanel(QWidget):
|
||||
self.fm_pos_group,
|
||||
self.sl2_pos_group,
|
||||
self.bm2_pos_group,
|
||||
self.es_pos_group,
|
||||
self.ot_pos_group,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -8,16 +8,18 @@ import os
|
||||
import numpy as np
|
||||
from collections import namedtuple
|
||||
|
||||
if os.environ.get("USE_XRT", "True").lower() in ("1", "true", "yes"):
|
||||
import xrt.backends.raycing.materials as rm # type: ignore
|
||||
else:
|
||||
class _DummyClass:
|
||||
def __init__(self, *args, **kwargs):
|
||||
pass
|
||||
class _DummyMaterials:
|
||||
Material = _DummyClass
|
||||
CrystalSi = _DummyClass
|
||||
rm = _DummyMaterials()
|
||||
import xrt.backends.raycing.materials as rm
|
||||
|
||||
# if os.environ.get("USE_XRT", "True").lower() in ("1", "true", "yes"):
|
||||
# import xrt.backends.raycing.materials as rm # type: ignore
|
||||
# else:
|
||||
# class _DummyClass:
|
||||
# def __init__(self, *args, **kwargs):
|
||||
# pass
|
||||
# class _DummyMaterials:
|
||||
# Material = _DummyClass
|
||||
# CrystalSi = _DummyClass
|
||||
# rm = _DummyMaterials()
|
||||
|
||||
# XRT definitions
|
||||
filterBeryl = rm.Material('Be', rho=1.85, kind='plate') # pyright: ignore[reportArgumentType]
|
||||
|
||||
@@ -50,7 +50,7 @@ class NumberIndicator(QWidget):
|
||||
self.label.setFixedWidth(150)
|
||||
layout.addWidget(self.label)
|
||||
self.val = QLabel('-')
|
||||
self.val.setFixedWidth(160)
|
||||
# self.val.setFixedWidth(140)
|
||||
layout.addWidget(self.val)
|
||||
self.unit = unit
|
||||
self.highlight = highlight
|
||||
@@ -68,7 +68,7 @@ class NumberIndicator(QWidget):
|
||||
|
||||
def setValue(self, number):
|
||||
self.number = number
|
||||
text = f'{number:.{self.decimals}f}'
|
||||
text = f'{number:.{int(self.decimals)}f}'
|
||||
if self.unit is not None:
|
||||
text = text + ' ' + self.unit
|
||||
self.val.setText(text)
|
||||
@@ -85,7 +85,7 @@ class InputTextField(QWidget):
|
||||
layout.addWidget(self.label)
|
||||
self.val = QLineEdit()
|
||||
self.val.setPlaceholderText('0')
|
||||
self.val.setFixedWidth(160)
|
||||
# self.val.setFixedWidth(140)
|
||||
layout.addWidget(self.val)
|
||||
|
||||
def set_text(self, text):
|
||||
@@ -104,7 +104,7 @@ class InputTextField(QWidget):
|
||||
)
|
||||
|
||||
class InputNumberField(QWidget):
|
||||
def __init__(self, label, init=0, decimals=1, single_step=0.1, ll=-1e6, hl=1e6):
|
||||
def __init__(self, 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)
|
||||
@@ -113,11 +113,11 @@ class InputNumberField(QWidget):
|
||||
self.label.setFixedWidth(150)
|
||||
layout.addWidget(self.label)
|
||||
self.val = QDoubleSpinBox()
|
||||
self.val.setValue(init)
|
||||
self.val.setRange(ll, hl)
|
||||
self.val.setDecimals(decimals)
|
||||
self.val.setSingleStep(single_step)
|
||||
self.val.setFixedWidth(160)
|
||||
self.val.setValue(init)
|
||||
# self.val.setFixedWidth(140)
|
||||
layout.addWidget(self.val)
|
||||
|
||||
def set_number(self, number):
|
||||
@@ -204,7 +204,7 @@ class ComboBox(QWidget):
|
||||
self.label.setFixedWidth(150)
|
||||
layout.addWidget(self.label)
|
||||
self.value = QComboBox()
|
||||
self.value.setFixedWidth(160)
|
||||
# self.value.setFixedWidth(140)
|
||||
for entry in enums:
|
||||
self.value.addItem(entry)
|
||||
layout.addWidget(self.value)
|
||||
|
||||
Reference in New Issue
Block a user