refactoring
CI for debye_bec / test (pull_request) Failing after 1m4s
CI for debye_bec / test (push) Failing after 1m5s

This commit is contained in:
x01da
2026-05-07 07:32:43 +02:00
parent 6da7e665b3
commit 0365d6eac7
4 changed files with 125 additions and 123 deletions
@@ -8,34 +8,34 @@ def calc_sideview(cfg):
# beam height (Y=height, Z=along beam)
beam = {}
beam['Z'] = []
beam['Y'] = []
beam['Z'].append(0) # Source
beam['Y'].append(bl.sourceHeight)
beam['Z'].append(bl.cm.center[1]) # CM
beam['Y'].append(bl.sourceHeight)
beam['x'] = []
beam['y'] = []
beam['x'].append(0) # Source
beam['y'].append(bl.sourceHeight)
beam['x'].append(bl.cm.center[1]) # CM
beam['y'].append(bl.sourceHeight)
if cfg['mo1_mode'] in 'Monochromatic':
diag = bl.mo1.xtalGap[0]/np.sin(cfg['mo1_bragg']) # Calculations for Mono
dy = diag*np.sin(2*(cfg['cm_pitch']+cfg['mo1_bragg']))
dz = diag*np.cos(2*(cfg['cm_pitch']+cfg['mo1_bragg']))
beam['Z'].append(bl.mo1.center[1]-dz/2) # Mono 1.1
beam['Y'].append(bl.sourceHeight+np.tan(2*cfg['cm_pitch'])*(bl.mo1.center[1]-dz/2-bl.cm.center[1]))
beam['Z'].append(bl.mo1.center[1]+dz/2) # Mono 1.2
beam['Y'].append(bl.sourceHeight+np.tan(2*cfg['cm_pitch'])*(bl.mo1.center[1]-dz/2-bl.cm.center[1])+dy)
beam['Z'].append(bl.fm.center[1]) # FM
beam['Y'].append(bl.sourceHeight+np.tan(2*cfg['cm_pitch'])*(bl.fm.center[1]-bl.cm.center[1]-dz)+dy)
beam['Z'].append(cfg['smpl']) # Experiment
beam['Y'].append(bl.sourceHeight+np.tan(2*cfg['cm_pitch'])*(bl.fm.center[1]-bl.cm.center[1]-dz)+dy+np.tan(2*(cfg['cm_pitch']-cfg['fm_pitch']))*(cfg['smpl']-bl.fm.center[1]))
beam['x'].append(bl.mo1.center[1]-dz/2) # Mono 1.1
beam['y'].append(bl.sourceHeight+np.tan(2*cfg['cm_pitch'])*(bl.mo1.center[1]-dz/2-bl.cm.center[1]))
beam['x'].append(bl.mo1.center[1]+dz/2) # Mono 1.2
beam['y'].append(bl.sourceHeight+np.tan(2*cfg['cm_pitch'])*(bl.mo1.center[1]-dz/2-bl.cm.center[1])+dy)
beam['x'].append(bl.fm.center[1]) # FM
beam['y'].append(bl.sourceHeight+np.tan(2*cfg['cm_pitch'])*(bl.fm.center[1]-bl.cm.center[1]-dz)+dy)
beam['x'].append(cfg['smpl']) # Experiment
beam['y'].append(bl.sourceHeight+np.tan(2*cfg['cm_pitch'])*(bl.fm.center[1]-bl.cm.center[1]-dz)+dy+np.tan(2*(cfg['cm_pitch']-cfg['fm_pitch']))*(cfg['smpl']-bl.fm.center[1]))
elif cfg['mo1_mode'] == 'Pinkbeam':
beam['Z'].append(bl.fm.center[1]) # FM
beam['Y'].append(bl.sourceHeight+np.tan(2*cfg['cm_pitch'])*(bl.fm.center[1]-bl.cm.center[1]))
beam['Z'].append(cfg['smpl']) # Experiment
beam['Y'].append(bl.sourceHeight+np.tan(2*cfg['cm_pitch'])*(bl.fm.center[1]-bl.cm.center[1])+np.tan(2*(cfg['cm_pitch']-cfg['fm_pitch']))*(cfg['smpl']-bl.fm.center[1]))
beam['x'].append(bl.fm.center[1]) # FM
beam['y'].append(bl.sourceHeight+np.tan(2*cfg['cm_pitch'])*(bl.fm.center[1]-bl.cm.center[1]))
beam['x'].append(cfg['smpl']) # Experiment
beam['y'].append(bl.sourceHeight+np.tan(2*cfg['cm_pitch'])*(bl.fm.center[1]-bl.cm.center[1])+np.tan(2*(cfg['cm_pitch']-cfg['fm_pitch']))*(cfg['smpl']-bl.fm.center[1]))
dy_fm_ex = beam['Y'][-1] - beam['Y'][-2]
dz_fm_ex = beam['Z'][-1] - beam['Z'][-2]
dz_fm_win = bl.ehWindow.center[1] - beam['Z'][-2]
h_at_win = beam['Y'][-2] + dy_fm_ex / dz_fm_ex * dz_fm_win
dy_fm_ex = beam['y'][-1] - beam['y'][-2]
dz_fm_ex = beam['x'][-1] - beam['x'][-2]
dz_fm_win = bl.ehWindow.center[1] - beam['x'][-2]
h_at_win = beam['y'][-2] + dy_fm_ex / dz_fm_ex * dz_fm_win
beam['heightWindow'] = h_at_win
@@ -1,43 +1,9 @@
import sys
import re
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,
QApplication,
QLayout,
)
# pylint: disable=E0611
from qtpy.QtCore import (
Qt,
QTimer,
)
from qtpy.QtGui import (
QColor,
QBrush,
)
import pyqtgraph as pg
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,
Mover,
)
from debye_bec.bec_widgets.widgets.digital_twin.calc_positions import calc_positions
from debye_bec.bec_widgets.widgets.digital_twin.calc_sideview import calc_sideview
from debye_bec.bec_widgets.widgets.digital_twin.calc_surfaces import calc_surfaces
import debye_bec.bec_widgets.widgets.x01da_parameters as bl
logger = bec_logger.logger
@@ -171,3 +137,66 @@ def cm_critical_angle(cm_stripe, energy):
numberDensity = stripe.rho*1e3*AVOGADRO/(stripe.elements[0].mass/1e3)
criticalAngle = np.sqrt(numberDensity*2.8179e-15*w**2*f1/np.pi)
return criticalAngle
def mirror_surface_geometries(mirror):
if mirror in "cm":
surface = bl.cm.surface
limOptX = bl.cm.limOptX
limOptY = bl.cm.limOptY
elif mirror in 'fm_toroid':
surface = bl.fm.surfaceToroid
limOptX = bl.fm.limOptXToroid
limOptY = bl.fm.limOptYToroid
elif mirror in 'fm_flat':
surface = bl.fm.surfaceFlat
limOptX = bl.fm.limOptXFlat
limOptY = bl.fm.limOptYFlat
else:
raise ValueError(f'Requested mirror {mirror} not available!')
geom = {}
for sf, lx, hx, ly, hy in zip(surface, limOptX[0], limOptX[1], limOptY[0], limOptY[1]):
geom[sf] = (lx, ly, hx-lx, hy-ly)
return geom
def mo_surface_geometries(mo, plane):
if mo in 'mo1':
xtal = bl.mo1.xtal
xtal_width = bl.mo1.xtalWidth
xtal_offset_x = bl.mo1.xtalOffsetX
if plane == 0:
xtal_length = bl.mo1.xtalLength1
else:
xtal_length = bl.mo1.xtalLength2
else:
raise ValueError(f'Requested mono {mo} not available!')
geom = {}
for sf, w, offx, length in zip(xtal, xtal_width, xtal_offset_x, xtal_length):
geom[sf] = (offx-w/2, -length/2, w, length)
return geom
def wall_geometries():
geom = []
for i, _ in enumerate(bl.walls.start):
geom.append([
bl.walls.start[i],
bl.walls.height[i][0],
bl.walls.end[i] - bl.walls.start[i],
bl.walls.height[i][1] - bl.walls.height[i][0],
])
return geom
def pipe_geometries():
pipes = []
for i, _ in enumerate(bl.vacuum_pipes.center):
top = bl.vacuum_pipes.center[i] + bl.vacuum_pipes.diameter[i]/2 + bl.sourceHeight
bottom = bl.vacuum_pipes.center[i] - bl.vacuum_pipes.diameter[i]/2 + bl.sourceHeight
pipes.append({
'x': np.array([bl.vacuum_pipes.start[i], bl.vacuum_pipes.end[i]]),
'y': np.array([top, top])
})
pipes.append({
'x': np.array([bl.vacuum_pipes.start[i], bl.vacuum_pipes.end[i]]),
'y': np.array([bottom, bottom])
})
return pipes
@@ -3,10 +3,7 @@ Digital Twin: Custom BEC widget to support the beamline alignment.
"""
import sys
import re
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
@@ -51,10 +48,12 @@ from debye_bec.bec_widgets.widgets.digital_twin.calc_varia import (
mo1_bragg_angle,
fm_ideal_pitch,
cm_critical_angle,
mirror_surface_geometries,
mo_surface_geometries,
wall_geometries,
pipe_geometries,
)
import debye_bec.bec_widgets.widgets.x01da_parameters as bl
logger = bec_logger.logger
class DigitalTwin(BECWidget, QWidget):
@@ -245,21 +244,24 @@ class DigitalTwin(BECWidget, QWidget):
self.input.fm_pitch_ideal.setVisible(True)
self.input.fm_focx.setVisible(False)
self.input.fm_focy.setVisible(False)
self.input.fm_pitch_ideal.setLabel('Incidence Angle for focused beam')
elif fm_focus in 'Focused':
self.input.fm_pitch.setVisible(False)
self.input.fm_pitch_ideal.setVisible(True)
self.input.fm_focx.setVisible(False)
self.input.fm_focy.setVisible(False)
self.input.fm_pitch_ideal.setLabel('Incidence Angle for focused beam')
else: # Defocused
self.input.fm_pitch.setVisible(False)
self.input.fm_pitch_ideal.setVisible(True)
self.input.fm_focx.setVisible(True)
self.input.fm_focy.setVisible(True)
self.input.fm_pitch_ideal.setLabel('Incidence Angle for defocused beam')
def calc_reality(self):
config = self.get_reality_config()
beam = calc_sideview(config)
data = {'x': beam['Z'], 'y': beam['Y']} # TODO: Refactor sideview calculator to match data format
data = {'x': beam['x'], 'y': beam['y']}
self.sideview_plot.update_curves('reality', data)
surfaces = calc_surfaces(config)
self.surface_plots.update_surfaces(scene='reality', data=surfaces)
@@ -298,7 +300,7 @@ class DigitalTwin(BECWidget, QWidget):
def calc_assistant_sideview(self):
beam = calc_sideview(self.get_assistant_config())
data = {'x': beam['Z'], 'y': beam['Y']}
data = {'x': beam['x'], 'y': beam['y']}
self.sideview_plot.update_curves('assistant', data)
def calc_assistant_surfaces(self):
@@ -382,11 +384,11 @@ class InputPanel(QWidget):
self._layout.setSizeConstraint(QLayout.SetFixedSize) # type: ignore
# Energy
self.energy = InputNumberField('energy', 'Energy [eV]', init=8979, decimals=0, single_step=100, ll=4000, hl=65000)
self.energy = InputNumberField('energy', 'Energy', unit='eV', init=8979, decimals=0, single_step=100, ll=4000, hl=65000)
# FE Slits Acceptance
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_hacc = InputNumberField('h_acc', 'Horizontal', unit='mrad', prefix='±', init=0.25, decimals=2, single_step=0.01, ll=-0.1, hl=0.9)
self.sldi_vacc = InputNumberField('v_acc', 'Vertical', unit='mrad', prefix='±', init=0.1, decimals=2, single_step=0.01, ll=-0.1, hl=0.5)
self.sldi_ass_group = Group(
'FE Slits Acceptance',
[
@@ -397,7 +399,7 @@ class InputPanel(QWidget):
# Collimating mirror
self.cm_stripe = ComboBox('cm_stripe', 'Stripe', ['Si', 'Rh', 'Pt'])
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_pitch = InputNumberField('cm_pitch', 'Pitch', unit='mrad', init=-2.391, decimals=3, single_step=0.01, ll=-4.6, hl=-1.2)
self.cm_pitch_critical = NumberIndicator('Critical Pitch', 'mrad', decimals=3)
self.cm_refl = NumberIndicator('Reflectivity at x eV', '%', decimals=0)
self.cm_refl_harm = NumberIndicator('Reflectivity at x eV', '%', decimals=0)
@@ -430,9 +432,9 @@ class InputPanel(QWidget):
# Focusing Mirror
self.fm_stripe = ComboBox('fm_stripe', 'Stripe', ['Rh (toroid)', 'Rh (flat)', 'Pt (toroid)', 'Pt (flat)'])
self.fm_focus = ComboBox('fm_focus', 'Focus Type', ['Manual', 'Focused', 'Defocused'])
self.fm_pitch = InputNumberField('fm_pitch', 'Incidence Angle [mrad]', init=-2.391, decimals=3, single_step=0.01, ll=-10, hl=2)
self.fm_focx = InputNumberField('fm_focx', 'Beam Size Horizontal [mm]', init=1, decimals=1, single_step=0.1, ll=0, hl=30)
self.fm_focy = InputNumberField('fm_focy', 'Beam Size Vertical [mm]', init=1, decimals=1, single_step=0.1, ll=0, hl=10)
self.fm_pitch = InputNumberField('fm_pitch', 'Incidence Angle', unit='mrad', init=-2.391, decimals=3, single_step=0.01, ll=-10, hl=2)
self.fm_focx = InputNumberField('fm_focx', 'Beam Size Horizontal', unit='mm', init=1, decimals=1, single_step=0.1, ll=0, hl=30)
self.fm_focy = InputNumberField('fm_focy', 'Beam Size Vertical', unit='mm', init=1, decimals=1, single_step=0.1, ll=0, hl=10)
self.fm_pitch_ideal = NumberIndicator('Incidence Angle for focused beam', 'mrad', decimals=3)
self.fm_refl = NumberIndicator('Reflectivity at x eV', '%', decimals=0)
self.fm_refl_harm = NumberIndicator('Reflectivity at x eV', '%', decimals=0)
@@ -452,7 +454,7 @@ class InputPanel(QWidget):
# Sample
self.cm_fm_harm_suppr = NumberIndicator('Total Suppression Factor at x eV', '', decimals=0)
self.smpl = InputNumberField('smpl', 'Sample Position [mm]', init=23511, decimals=0, single_step=100, ll=23000, hl=30000)
self.smpl = InputNumberField('smpl', 'Sample Position', unit='mm', init=23511, decimals=0, single_step=100, ll=23000, hl=30000)
# Assemble complete assitant group
self.input_group = Group(
@@ -767,52 +769,29 @@ class SurfacePlots(QWidget):
def plot_walls(self):
def plot_mirror_stripe(widget, surface, limOptX, limOptY):
for sf, lx, hx, ly, hy in zip(surface, limOptX[0], limOptX[1], limOptY[0], limOptY[1]):
rect = pg.QtWidgets.QGraphicsRectItem( # pylint: disable=E1101
lx,
ly,
hx - lx,
hy - ly,
)
def plot_surface(widget, surfaces):
for name, surface in surfaces.items():
rect = pg.QtWidgets.QGraphicsRectItem(*surface) # pylint: disable=E1101
rect.setBrush(pg.QtGui.QBrush(pg.QtGui.QColor(*self.color_impenetrable))) # pylint: disable=E1101
rect.setPen(pg.mkPen(color=self.color_impenetrable, width=2))
widget.addItem(rect)
text = pg.TextItem(sf, color=self.text_color, anchor=(0.5, 0.5))
text = pg.TextItem(name, color=self.text_color, anchor=(0.5, 0.5))
widget.addItem(text)
text.setPos((hx+lx)/2, (hy+ly)/2)
text.setZValue(10)
self.walls.append(rect)
self.texts.append(text)
def plot_mono_surface(widget, xtal, xtalWidth, xtalOffsetX, xtalLength):
for sf, w, offx, length in zip(xtal, xtalWidth, xtalOffsetX, xtalLength):
rect = pg.QtWidgets.QGraphicsRectItem( # pylint: disable=E1101
offx - w/2,
-length/2,
w,
length,
)
rect.setBrush(pg.QtGui.QBrush(pg.QtGui.QColor(*self.color_impenetrable))) # pylint: disable=E1101
rect.setPen(pg.mkPen(color=self.color_impenetrable, width=2))
widget.addItem(rect)
text = pg.TextItem(sf, color=self.text_color, anchor=(0.5, 0.5))
widget.addItem(text)
text.setPos(offx, 0)
text.setPos(surface[0]+surface[2]/2, surface[1]+surface[3]/2)
text.setZValue(10)
self.walls.append(rect)
self.texts.append(text)
for name, plot in self.plots.items():
if name in 'cm':
plot_mirror_stripe(plot['widget'], bl.cm.surface, bl.cm.limOptX, bl.cm.limOptY)
plot_surface(plot['widget'], mirror_surface_geometries('cm'))
elif name in 'mo1_1':
plot_mono_surface(plot['widget'], bl.mo1.xtal, bl.mo1.xtalWidth, bl.mo1.xtalOffsetX, bl.mo1.xtalLength1)
plot_surface(plot['widget'], mo_surface_geometries ('mo1', 0))
elif name in 'mo1_2':
plot_mono_surface(plot['widget'], bl.mo1.xtal, bl.mo1.xtalWidth, bl.mo1.xtalOffsetX, bl.mo1.xtalLength2)
plot_surface(plot['widget'], mo_surface_geometries ('mo1', 1))
elif name in 'fm':
plot_mirror_stripe(plot['widget'], bl.fm.surfaceFlat, bl.fm.limOptXFlat, bl.fm.limOptYFlat)
plot_mirror_stripe(plot['widget'], bl.fm.surfaceToroid, bl.fm.limOptXToroid, bl.fm.limOptYToroid)
plot_surface(plot['widget'], mirror_surface_geometries('fm_flat'))
plot_surface(plot['widget'], mirror_surface_geometries('fm_toroid'))
else:
raise Exception(f'Plot {name} not found!')
for name, plot in self.plots.items():
@@ -929,32 +908,22 @@ class SideviewPlot(QWidget):
pipe.setPen(pg.mkPen(color=self.color_impenetrable, width=2))
def plot_vacuum_pipes(self):
for i, _ in enumerate(bl.vacuum_pipes.center):
top = bl.vacuum_pipes.center[i] + bl.vacuum_pipes.diameter[i]/2 + bl.sourceHeight
bottom = bl.vacuum_pipes.center[i] - bl.vacuum_pipes.diameter[i]/2 + bl.sourceHeight
pipes = pipe_geometries()
for pipe in pipes:
self.pipes.append(self.plot_widget.plot(
x=np.array([bl.vacuum_pipes.start[i], bl.vacuum_pipes.end[i]]),
y=np.array([top, top]),
pen=pg.mkPen(color=self.color_impenetrable, width=2),
))
self.pipes.append(self.plot_widget.plot(
x=np.array([bl.vacuum_pipes.start[i], bl.vacuum_pipes.end[i]]),
y=np.array([bottom, bottom]),
x=pipe['x'],
y=pipe['y'],
pen=pg.mkPen(color=self.color_impenetrable, width=2),
))
def plot_walls(self):
for i, _ in enumerate(bl.walls.start):
rect = pg.QtWidgets.QGraphicsRectItem( # pylint: disable=E1101
bl.walls.start[i],
bl.walls.height[i][0],
bl.walls.end[i] - bl.walls.start[i],
bl.walls.height[i][1] - bl.walls.height[i][0],
)
walls = wall_geometries()
for wall in walls:
rect = pg.QtWidgets.QGraphicsRectItem(*wall) # pylint: disable=E1101
rect.setBrush(pg.QtGui.QBrush(pg.QtGui.QColor(*self.color_impenetrable))) # pylint: disable=E1101
rect.setPen(pg.mkPen(color=self.color_impenetrable, width=2))
self.plot_widget.addItem(rect)
self.walls.append(rect)
self.walls.append(rect)
def update_curves(self, scene, data):
self.data[scene] = data
+5 -1
View File
@@ -113,7 +113,7 @@ class NumberIndicator(QWidget):
# )
class InputNumberField(QWidget):
def __init__(self, identifier='', label='', init=0.0, decimals=1, single_step=0.1, ll=-1e6, hl=1e6):
def __init__(self, identifier='', label='', unit=None, prefix=None, init=0.0, decimals=1, single_step=0.1, ll=-1e6, hl=1e6):
super().__init__()
layout = QHBoxLayout(self)
layout.setContentsMargins(10, 0, 0, 0)
@@ -129,6 +129,10 @@ class InputNumberField(QWidget):
self.val.setDecimals(decimals)
self.val.setSingleStep(single_step)
self.val.setValue(init)
if unit is not None:
self.val.setSuffix(' ' + unit)
if prefix is not None:
self.val.setPrefix(prefix + ' ')
# self.val.setFixedWidth(140)
layout.addWidget(self.val)