From ef4c82262c9a04aa88c1417edc92b32eaaf70e53 Mon Sep 17 00:00:00 2001 From: x01da Date: Tue, 19 May 2026 10:45:42 +0200 Subject: [PATCH] refactoring --- .../widgets/digital_twin/digital_twin.py | 100 +++- .../widgets/digital_twin/move_widget.py | 9 +- .../bec_widgets/widgets/digital_twin/plots.py | 14 +- .../widgets/digital_twin/settings_panel.py | 11 +- debye_bec/bec_widgets/widgets/qt_widgets.py | 126 +++-- .../bec_widgets/widgets/x01da_parameters.py | 450 +++++++++--------- 6 files changed, 411 insertions(+), 299 deletions(-) diff --git a/debye_bec/bec_widgets/widgets/digital_twin/digital_twin.py b/debye_bec/bec_widgets/widgets/digital_twin/digital_twin.py index 985c8f5..a9c87af 100644 --- a/debye_bec/bec_widgets/widgets/digital_twin/digital_twin.py +++ b/debye_bec/bec_widgets/widgets/digital_twin/digital_twin.py @@ -12,16 +12,19 @@ from bec_lib import bec_logger from bec_lib.endpoints import MessageEndpoints from bec_widgets.utils.bec_dispatcher import BECDispatcher from bec_widgets.utils.bec_widget import BECWidget -from bec_widgets.utils.colors import apply_theme +from bec_widgets.utils.colors import apply_theme, get_accent_colors from bec_widgets.utils.error_popups import SafeSlot # pylint: disable=E0611 from qtpy.QtCore import Qt, QTimer +from qtpy.QtGui import QFont from qtpy.QtWidgets import ( QApplication, QDialog, + QDialogButtonBox, QHBoxLayout, QLabel, + QPlainTextEdit, QPushButton, QStyle, QVBoxLayout, @@ -113,8 +116,8 @@ class DigitalTwin(BECWidget, QWidget): self.input.smpl.value_changed_connect(self.calc_assistant) self.input.adapt_reality.clicked_connect(self.adapt_reality) - self.settings.reload_offsets.clicked_connect(self.load_offsets) - self.settings.unload_offsets.clicked_connect(self.unload_offsets) + self.settings.load_offsets.clicked_connect(self.load_offsets) + self.settings.show_offsets.clicked_connect(self.show_offsets) self.bragg_angle = 0.0 self.qy = 0.0 @@ -294,13 +297,16 @@ class DigitalTwin(BECWidget, QWidget): self.calc_assistant_sideview() self.calc_assistant_surfaces() - def get_assistant_config(self, apply_offset: bool = False): + def get_assistant_config(self, apply_offset: bool = False) -> ConfigDict: """ Assembles the digital twin config from the assistants input. Args: apply_offset(bool): Applies the offset values to the config. Defaults to False + + Returns: + ConfigDict: config of the assistant """ fm_focus = self.input.fm_focus.currentText() if fm_focus in "Manual": @@ -361,9 +367,12 @@ class DigitalTwin(BECWidget, QWidget): # logger.info(f'Config created: {config}') return config - def get_reality_config(self): + def get_reality_config(self) -> ConfigDict: """ Assembles the digital twin config based on the real axis positions. + + Returns: + ConfigDict: config of the reality """ mo1_trx = self.dev.mo1_trx.read(cached=True)["mo1_trx"]["value"] if abs(mo1_trx) > 5: @@ -505,34 +514,85 @@ class DigitalTwin(BECWidget, QWidget): @SafeSlot() def load_offsets(self, *_, recalculate: bool = True): """ - Loads the offsets from the file + Loads or unloads the offsets from the file Args: - recalculate(bool): Recalculates the assistant values. + recalculate(bool): Recalculates the assistant values after loading. Defaults to True """ - file = Path(OFFSET_FILE) - if not file.exists(): - raise FileNotFoundError(f"Offset file not found: {OFFSET_FILE}") - with file.open("r", encoding="utf-8") as f: - data = yaml.safe_load(f) + if self.offsets == {}: + # Load offsets + file = Path(OFFSET_FILE) + if not file.exists(): + raise FileNotFoundError(f"Offset file not found: {OFFSET_FILE}") - if not isinstance(data, dict): - raise ValueError(f"Expected a YAML mapping, got {type(data).__name__}") + with file.open("r", encoding="utf-8") as f: + data = yaml.safe_load(f) - self.offsets = data + if not isinstance(data, dict): + raise ValueError(f"Expected a YAML mapping, got {type(data).__name__}") - if recalculate: + self.offsets = data + + if recalculate: + self.calc_assistant(identifier="init") + + self.settings.load_offsets.setText("Unload") + self.settings.offsets_status.setText("Loaded and applied") + self.settings.offsets_status.setColor(get_accent_colors().success.name()) + self.settings.show_offsets.enable_button(True) + else: + # Unload offsets + self.offsets = {} self.calc_assistant(identifier="init") + self.settings.load_offsets.setText("Load") + self.settings.offsets_status.setText("No offsets") + self.settings.offsets_status.setColor(get_accent_colors().default.name()) + self.settings.show_offsets.enable_button(False) + @SafeSlot() - def unload_offsets(self, *_): + def show_offsets(self, *_): """ - Removes the offsets and recalculates the assistant values. + Shows the offsets in a popup window """ - self.offsets = {} - self.calc_assistant(identifier="init") + dialog = QDialog() + dialog.setWindowTitle("Digital Twin - Offsets") + dialog.setFixedWidth(500) + layout = QVBoxLayout(dialog) + layout.setSpacing(12) + layout.setContentsMargins(20, 20, 20, 20) + + intro_label = QLabel("The offsets are saved in the digital twin BEC widget folder:") + intro_label.setWordWrap(True) + layout.addWidget(intro_label) + + file = QLabel(OFFSET_FILE) + file.setWordWrap(True) + font = QFont() + font.setItalic(True) + file.setFont(font) + layout.addWidget(file) + + text_edit = QPlainTextEdit() + text_edit.setReadOnly(True) + text_edit.setFont(QFont("Consolas", 9)) + + class InlineListDumper(yaml.Dumper): + """YAML dumper that renders all sequences on a single line.""" + + def represent_sequence(self, tag, sequence, *_): + return super().represent_sequence(tag, sequence, flow_style=True) + + text_edit.setPlainText(yaml.dump(self.offsets, Dumper=InlineListDumper, sort_keys=False)) + layout.addWidget(text_edit) + + buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Close) + buttons.rejected.connect(dialog.reject) + layout.addWidget(buttons) + + dialog.exec() def update_fm_mode(self): """ diff --git a/debye_bec/bec_widgets/widgets/digital_twin/move_widget.py b/debye_bec/bec_widgets/widgets/digital_twin/move_widget.py index f11be4f..8266b58 100644 --- a/debye_bec/bec_widgets/widgets/digital_twin/move_widget.py +++ b/debye_bec/bec_widgets/widgets/digital_twin/move_widget.py @@ -62,8 +62,13 @@ class StatusIcon(QWidget): self.set_status(Status.NOT_IN_POSITION) - def get_rotation(self): - """Return the current rotation angle in degrees.""" + def get_rotation(self) -> float: + """ + Return the current rotation angle in degrees. + + Returns: + float: Rotation angle in deg + """ return self._rotation def set_rotation(self, angle: float): diff --git a/debye_bec/bec_widgets/widgets/digital_twin/plots.py b/debye_bec/bec_widgets/widgets/digital_twin/plots.py index 415fe6b..666abc2 100644 --- a/debye_bec/bec_widgets/widgets/digital_twin/plots.py +++ b/debye_bec/bec_widgets/widgets/digital_twin/plots.py @@ -2,7 +2,7 @@ Two plot classes to plot side-view and surface-view """ -from typing import Literal, Optional, TypedDict, cast +from typing import Literal, Optional, cast import numpy as np import pyqtgraph as pg @@ -13,7 +13,7 @@ from qtpy.QtCore import Qt from qtpy.QtGui import QBrush, QColor # pylint: disable=E0611 -from qtpy.QtWidgets import QApplication, QHBoxLayout, QVBoxLayout, QWidget +from qtpy.QtWidgets import QApplication, QGraphicsRectItem, QHBoxLayout, QVBoxLayout, QWidget from debye_bec.bec_widgets.widgets.digital_twin.calc_varia import ( mirror_surface_geometries, @@ -153,8 +153,8 @@ class SurfacePlots(QWidget): def plot_surface(widget, surfaces): for name, surface in surfaces.items(): - rect = pg.QtWidgets.QGraphicsRectItem(*surface) # pylint: disable=E1101 - rect.setBrush(QBrush(QColor(*self.color_impenetrable))) # pylint: disable=E1101 + rect = QGraphicsRectItem(*surface) + rect.setBrush(QBrush(QColor(*self.color_impenetrable))) rect.setPen(pg.mkPen(color=self.color_impenetrable, width=2)) widget.addItem(rect) text = pg.TextItem(name, color=self.text_color, anchor=(0.5, 0.5)) @@ -292,7 +292,7 @@ class SideviewPlot(QWidget): for wall in self.walls: wall.setPen(pg.mkPen(color=self.color_impenetrable, width=3)) - wall.setBrush(QBrush(QColor(*self.color_impenetrable))) # pylint: disable=E1101 + wall.setBrush(QBrush(QColor(*self.color_impenetrable))) for pipe in self.pipes: pipe.setPen(pg.mkPen(color=self.color_impenetrable, width=3)) @@ -311,8 +311,8 @@ class SideviewPlot(QWidget): """Plot walls""" walls = wall_geometries() for wall in walls: - rect = pg.QtWidgets.QGraphicsRectItem(*wall) # pylint: disable=E1101 - rect.setBrush(QBrush(QColor(*self.color_impenetrable))) # pylint: disable=E1101 + rect = QGraphicsRectItem(wall[0], wall[1], wall[2], wall[3]) + rect.setBrush(QBrush(QColor(*self.color_impenetrable))) rect.setPen(pg.mkPen(color=self.color_impenetrable, width=2)) self.plot_widget.addItem(rect) self.walls.append(rect) diff --git a/debye_bec/bec_widgets/widgets/digital_twin/settings_panel.py b/debye_bec/bec_widgets/widgets/digital_twin/settings_panel.py index 694e1b4..d715c65 100644 --- a/debye_bec/bec_widgets/widgets/digital_twin/settings_panel.py +++ b/debye_bec/bec_widgets/widgets/digital_twin/settings_panel.py @@ -5,7 +5,7 @@ Settings panel for the digital twin widget # pylint: disable=E0611 from qtpy.QtWidgets import QLayout, QVBoxLayout, QWidget -from debye_bec.bec_widgets.widgets.qt_widgets import Button, Group +from debye_bec.bec_widgets.widgets.qt_widgets import Button, Group, TextIndicator class SettingsPanel(QWidget): @@ -17,11 +17,14 @@ class SettingsPanel(QWidget): self._layout.setSizeConstraint(QLayout.SetFixedSize) # type: ignore # Reload offsets - self.reload_offsets = Button(label="Reload Offsets", label_button="Reload", enabled=True) - self.unload_offsets = Button(label="Unload Offsets", label_button="Unload", enabled=True) + self.load_offsets = Button(label="Load Offsets", label_button="Load", enabled=True) + self.offsets_status = TextIndicator(label="Offsets") + self.show_offsets = Button(label="Show Offsets", label_button="Show", enabled=True) # Assemble complete offset group - self.offset_group = Group("Axes Offsets", [self.reload_offsets, self.unload_offsets]) + self.offset_group = Group( + "Axes Offsets", [self.load_offsets, self.offsets_status, self.show_offsets] + ) self._layout.addWidget(self.offset_group) self._layout.addStretch() diff --git a/debye_bec/bec_widgets/widgets/qt_widgets.py b/debye_bec/bec_widgets/widgets/qt_widgets.py index 201e72f..5a0f59b 100644 --- a/debye_bec/bec_widgets/widgets/qt_widgets.py +++ b/debye_bec/bec_widgets/widgets/qt_widgets.py @@ -1,24 +1,37 @@ +""" +Universal Qt widgets +""" from functools import partial -# pylint: disable=E0611 -from qtpy.QtWidgets import ( - QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, - QPushButton, QGroupBox, QComboBox, QApplication, QDoubleSpinBox -) -from qtpy.QtGui import QFont -from qtpy.QtCore import Qt from bec_widgets.utils.colors import get_accent_colors +from qtpy.QtCore import Qt + +# pylint: disable=E0611 +from qtpy.QtGui import QFont +from qtpy.QtWidgets import ( + QApplication, + QComboBox, + QDoubleSpinBox, + QGroupBox, + QHBoxLayout, + QLabel, + QPushButton, + QVBoxLayout, + QWidget, +) + class Group(QGroupBox): def __init__(self, label, widgets): super().__init__(label) - self.layout = QVBoxLayout(self) # type: ignore + self.layout = QVBoxLayout(self) # type: ignore for widget in widgets: - self.layout.addWidget(widget) # type: ignore + self.layout.addWidget(widget) # type: ignore + 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) @@ -28,8 +41,8 @@ class NumberIndicator(QWidget): self.label.setContentsMargins(0, 0, 10, 0) self.label.setWordWrap(True) layout.addWidget(self.label) - self.val = QLabel('-') - self.val.setAlignment(Qt.AlignTop) # type: ignore + self.val = QLabel("-") + self.val.setAlignment(Qt.AlignTop) # type: ignore # self.val.setFixedWidth(140) layout.addWidget(self.val) self.unit = unit @@ -51,13 +64,25 @@ class NumberIndicator(QWidget): def setValue(self, number): self.number = number - text = f'{number:.{int(self.decimals)}f}' + text = f"{number:.{int(self.decimals)}f}" if self.unit is not None: - text = text + ' ' + self.unit + text = text + " " + self.unit self.val.setText(text) + class InputNumberField(QWidget): - def __init__(self, identifier='', label='', unit=None, prefix=None, 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) @@ -74,9 +99,9 @@ class InputNumberField(QWidget): self.val.setSingleStep(single_step) self.val.setValue(init) if unit is not None: - self.val.setSuffix(' ' + unit) + self.val.setSuffix(" " + unit) if prefix is not None: - self.val.setPrefix(prefix + ' ') + self.val.setPrefix(prefix + " ") # self.val.setFixedWidth(140) layout.addWidget(self.val) @@ -85,18 +110,21 @@ class InputNumberField(QWidget): def has_focus(self) -> bool: return self.val.hasFocus() - + def value(self) -> float: return self.val.value() def value_changed_connect(self, func): """Connect a function to the Enter/Return key press.""" self.val.valueChanged.connect( - partial(func, identifier=self.identifier, value_obj=self.val, value=lambda: self.val.value()) + partial( + func, identifier=self.identifier, value_obj=self.val, value=lambda: self.val.value() + ) ) + class ComboBox(QWidget): - def __init__(self, identifier='', label='', enums=[]): + def __init__(self, identifier="", label="", enums=[]): super().__init__() layout = QHBoxLayout(self) layout.setContentsMargins(10, 0, 0, 0) @@ -124,14 +152,20 @@ class ComboBox(QWidget): def activated_connect(self, func): """Connect a function to the Enter/Return key press.""" self.value.activated.connect( - partial(func, identifier=self.identifier, value_obj=self.value, 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 Button(QWidget): - def __init__(self, label=None, label_button:str='', enabled=False): + def __init__(self, label=None, label_button: str = "", enabled=False): super().__init__() layout = QHBoxLayout(self) layout.setContentsMargins(10, 0, 0, 0) @@ -165,31 +199,31 @@ class Button(QWidget): def setText(self, text): self.button.setText(text) -# class TextIndicator(QWidget): -# def __init__(self, label, unit=None, highlight=False): -# 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.value = QLabel('-') -# self.value.setFixedWidth(160) -# layout.addWidget(self.value) -# self.unit = unit -# self.highlight = highlight -# if highlight: -# font = QFont() -# font.setBold(True) -# font.setPointSize(14) -# self.label.setFont(font) -# self.value.setFont(font) -# def set_text(self, text): -# if self.unit is not None: -# text = text + ' ' + self.unit -# self.value.setText(text) +class TextIndicator(QWidget): + def __init__(self, label): + super().__init__() + 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.text = QLabel("-") + self.text.setAlignment(Qt.AlignTop) # type: ignore + layout.addWidget(self.text) + + def setLabel(self, label) -> None: + self.label.setText(label) + + def setText(self, text): + self.text.setText(text) + + def setColor(self, color: str): + self.text.setStyleSheet(f"QLabel {{color:{color}}}") + # class Button(QWidget): # def __init__(self, label, label_button): diff --git a/debye_bec/bec_widgets/widgets/x01da_parameters.py b/debye_bec/bec_widgets/widgets/x01da_parameters.py index 8a97e5a..630d7fc 100644 --- a/debye_bec/bec_widgets/widgets/x01da_parameters.py +++ b/debye_bec/bec_widgets/widgets/x01da_parameters.py @@ -4,138 +4,123 @@ This file describes the parameter of each component of the Debye beamline to be used for raytracing and geometrical calculations. """ -import os -import numpy as np from collections import namedtuple +import numpy as np 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] -filterDiamond = rm.Material('C', rho=3.52, kind='plate') # pyright: ignore[reportArgumentType] -filterGraphite = rm.Material('C', rho=2.266, kind='plate') # pyright: ignore[reportArgumentType] +filterBeryl = rm.Material("Be", rho=1.85, kind="plate") # pyright: ignore[reportArgumentType] +filterDiamond = rm.Material("C", rho=3.52, kind="plate") # pyright: ignore[reportArgumentType] +filterGraphite = rm.Material("C", rho=2.266, kind="plate") # pyright: ignore[reportArgumentType] -stripeSi = rm.Material('Si', rho=2.33) # pyright: ignore[reportArgumentType] -stripePt = rm.Material('Pt', rho=21.45) # pyright: ignore[reportArgumentType] -stripeRh = rm.Material('Rh', rho=12.41) # pyright: ignore[reportArgumentType] -stripeCr = rm.Material('Cr', rho=7.14) # pyright: ignore[reportArgumentType] -stripePyrex = rm.Material('Si', rho=2.20) # Use Si as bare element and the density of SiO2 # pyright: ignore[reportArgumentType] +stripeSi = rm.Material("Si", rho=2.33) # pyright: ignore[reportArgumentType] +stripePt = rm.Material("Pt", rho=21.45) # pyright: ignore[reportArgumentType] +stripeRh = rm.Material("Rh", rho=12.41) # pyright: ignore[reportArgumentType] +stripeCr = rm.Material("Cr", rho=7.14) # pyright: ignore[reportArgumentType] +stripePyrex = rm.Material( + "Si", rho=2.20 +) # Use Si as bare element and the density of SiO2 # pyright: ignore[reportArgumentType] -si111_1 = rm.CrystalSi(hkl=(1, 1, 1), tK=77) # first xtal surface -si311_1 = rm.CrystalSi(hkl=(3, 1, 1), tK=77) # first xtal surface -si333_1 = rm.CrystalSi(hkl=(3, 3, 3), tK=77) # first xtal surface -si511_1 = rm.CrystalSi(hkl=(5, 1, 1), tK=77) # first xtal surface -si111_2 = rm.CrystalSi(hkl=(1, 1, 1), tK=77) # second xtal surface -si311_2 = rm.CrystalSi(hkl=(3, 1, 1), tK=77) # second xtal surface -si333_2 = rm.CrystalSi(hkl=(3, 3, 3), tK=77) # second xtal surface -si511_2 = rm.CrystalSi(hkl=(5, 1, 1), tK=77) # second xtal surface +si111_1 = rm.CrystalSi(hkl=(1, 1, 1), tK=77) # first xtal surface +si311_1 = rm.CrystalSi(hkl=(3, 1, 1), tK=77) # first xtal surface +si333_1 = rm.CrystalSi(hkl=(3, 3, 3), tK=77) # first xtal surface +si511_1 = rm.CrystalSi(hkl=(5, 1, 1), tK=77) # first xtal surface +si111_2 = rm.CrystalSi(hkl=(1, 1, 1), tK=77) # second xtal surface +si311_2 = rm.CrystalSi(hkl=(3, 1, 1), tK=77) # second xtal surface +si333_2 = rm.CrystalSi(hkl=(3, 3, 3), tK=77) # second xtal surface +si511_2 = rm.CrystalSi(hkl=(5, 1, 1), tK=77) # second xtal surface -filterDiamond = rm.Material('C', rho=3.52, kind='plate') # pyright: ignore[reportArgumentType] -filterBe = rm.Material('Be', rho=1.85, kind='plate') # pyright: ignore[reportArgumentType] -filterSi3N4 = rm.Material(['Si', 'N'], quantities=[3, 4], rho=3.44, kind='plate') # pyright: ignore[reportArgumentType] -filterAl = rm.Material('Al', rho=2.69, kind='plate') # pyright: ignore[reportArgumentType] -filterGraphite = rm.Material('C', rho=2.266, kind='plate') # pyright: ignore[reportArgumentType] +filterDiamond = rm.Material("C", rho=3.52, kind="plate") # pyright: ignore[reportArgumentType] +filterBe = rm.Material("Be", rho=1.85, kind="plate") # pyright: ignore[reportArgumentType] +filterSi3N4 = rm.Material( + ["Si", "N"], quantities=[3, 4], rho=3.44, kind="plate" +) # pyright: ignore[reportArgumentType] +filterAl = rm.Material("Al", rho=2.69, kind="plate") # pyright: ignore[reportArgumentType] +filterGraphite = rm.Material("C", rho=2.266, kind="plate") # pyright: ignore[reportArgumentType] # General parameters sourceHeight = 0 -#Synchrotron -synchrotron = namedtuple('synchrotron', ['eE', 'eI', 'eEspread', - 'eEpsilonX', 'eEpsilonZ', 'betaX', 'betaZ']) +# Synchrotron +synchrotron = namedtuple( + "synchrotron", ["eE", "eI", "eEspread", "eEpsilonX", "eEpsilonZ", "betaX", "betaZ"] +) sls1 = synchrotron( - eE = 2.4, - eI = 0.4, - eEspread=0.878e-3, - eEpsilonX=5.63, - eEpsilonZ=0.007, - betaX=0.45, - betaZ=14.4, - ) - -sls2 = synchrotron( - eE=2.7, - eI=0.4, - eEspread=1.147e-3, - eEpsilonX=0.156, - eEpsilonZ=0.01, - betaX=0.18, - betaZ=4.6, - ) - -# Source -bendingMagnet = namedtuple('bendingMagnet', ['name', 'center', 'sync', 'B0']) + eE=2.4, eI=0.4, eEspread=0.878e-3, eEpsilonX=5.63, eEpsilonZ=0.007, betaX=0.45, betaZ=14.4 +) + +sls2 = synchrotron( + eE=2.7, eI=0.4, eEspread=1.147e-3, eEpsilonX=0.156, eEpsilonZ=0.01, betaX=0.18, betaZ=4.6 +) + +# Source +bendingMagnet = namedtuple("bendingMagnet", ["name", "center", "sync", "B0"]) + +sls1_14t = bendingMagnet(name="FE-BM-SLS1-1.4T", center=(0, 0, 0), sync=sls1, B0=1.4) + +sls2_21t = bendingMagnet(name="FE-BM-SLS2-2.1T", center=(0, 0, 0), sync=sls2, B0=2.1) + +sls2_35t = bendingMagnet(name="FE-BM-SLS2-3.5T", center=(0, 0, 0), sync=sls2, B0=3.5) + +sls2_50t = bendingMagnet(name="FE-BM-SLS2-5.0T", center=(0, 0, 0), sync=sls2, B0=5.0) -sls1_14t = bendingMagnet( - name='FE-BM-SLS1-1.4T', - center=(0, 0, 0), - sync=sls1, - B0=1.4,) - -sls2_21t = bendingMagnet( - name='FE-BM-SLS2-2.1T', - center=(0, 0, 0), - sync=sls2, - B0=2.1,) - -sls2_35t = bendingMagnet( - name='FE-BM-SLS2-3.5T', - center=(0, 0, 0), - sync=sls2, - B0=3.5,) - -sls2_50t = bendingMagnet( - name='FE-BM-SLS2-5.0T', - center=(0, 0, 0), - sync=sls2, - B0=5.0,) - # FE slits -fe_slits = namedtuple('slits', ['name', 'center', 'center1', 'center2', 'maxDivH', 'maxDivV']) +fe_slits = namedtuple("slits", ["name", "center", "center1", "center2", "maxDivH", "maxDivV"]) feSlits = fe_slits( - name='FE-SLITS', + name="FE-SLITS", center=(0, 6117, sourceHeight), center1=(0, 5045, sourceHeight), center2=(0, 5289.5, sourceHeight), maxDivH=1.8e-3, - maxDivV=0.8e-3,) - + maxDivV=0.8e-3, +) + # FE Window -filt = namedtuple('filt', ['name', 'center', 'pitch', 'limPhysX', 'limPhysY', 'surface', 'material', 'thickness']) +filt = namedtuple( + "filt", ["name", "center", "pitch", "limPhysX", "limPhysY", "surface", "material", "thickness"] +) feWindow = filt( - name='FE-WINDOW', - center=(0., 7020, sourceHeight), - pitch=np.pi/2, + name="FE-WINDOW", + center=(0.0, 7020, sourceHeight), + pitch=np.pi / 2, limPhysX=(-6, 6), - limPhysY=(-3., 3.), - surface='None', + limPhysY=(-3.0, 3.0), + surface="None", material=filterDiamond, - thickness=0.1,) -feWindow = feWindow._replace(surface=f'CVD Diamond window {feWindow.thickness*1e3:0.0f} $\\mu$m') + thickness=0.1, +) +feWindow = feWindow._replace(surface=f"CVD Diamond window {feWindow.thickness*1e3:0.0f} $\\mu$m") + +# Collimating mirror +collimatingMirror = namedtuple( + "collimatingMirror", + [ + "name", + "center", + "surface", + "material", + "limPhysX", + "limPhysY", + "limOptX", + "limOptY", + "R", + "pitch", + "jack1", + "jack2", + "jack3", + "tx1", + "tx2", + ], +) -# Collimating mirror -collimatingMirror = namedtuple('collimatingMirror', ['name', - 'center', 'surface', 'material', 'limPhysX', 'limPhysY', - 'limOptX', 'limOptY', 'R', 'pitch', 'jack1', 'jack2', 'jack3', - 'tx1', 'tx2']) - cm = collimatingMirror( - name='FE-CM', + name="FE-CM", center=[0, 6890, sourceHeight], - surface=('Si','Pt','Rh'), + surface=("Si", "Pt", "Rh"), material=(stripeSi, stripePt, stripeRh), limPhysX=(-34, 34), limPhysY=(-600, 600), @@ -143,169 +128,194 @@ cm = collimatingMirror( limOptY=((-500, -500, -500), (500, 500, 500)), R=[3e6, 15e6], pitch=[-5.0e-3, -0.0e-3], - jack1=[0., 7210., 0.], #Tripod X, Y, Z (global) - jack2=[-210., 8310., 0.], - jack3=[210., 8310., 0.], - tx1=[0.0, -575.5], # X-Stage 1 [x, y] (local) - tx2=[0.0, 575],) # X-Stage 2 - -apertures = namedtuple('apertures', ['name', 'center', 'opening']) + jack1=[0.0, 7210.0, 0.0], # Tripod X, Y, Z (global) + jack2=[-210.0, 8310.0, 0.0], + jack3=[210.0, 8310.0, 0.0], + tx1=[0.0, -575.5], # X-Stage 1 [x, y] (local) + tx2=[0.0, 575], +) # X-Stage 2 + +apertures = namedtuple("apertures", ["name", "center", "opening"]) fePS = apertures( - name='FE-PS', - center=[0, 8815, sourceHeight], - opening=[-20., 20., -20.+12.5, 20.+12.5]) # left, right, bottom, top - + name="FE-PS", center=[0, 8815, sourceHeight], opening=[-20.0, 20.0, -20.0 + 12.5, 20.0 + 12.5] +) # left, right, bottom, top + opWbBsBlock = apertures( - name='OP-WB-BS-BLOCK', - center=[0., 13860, sourceHeight], - opening=[-18., 18., 25, 85.5]) # left, right, bottom, top - # opening=[-18., 18., 42, 76], # X10DA + name="OP-WB-BS-BLOCK", center=[0.0, 13860, sourceHeight], opening=[-18.0, 18.0, 25, 85.5] +) # left, right, bottom, top +# opening=[-18., 18., 42, 76], # X10DA # Monochromator -monochromator = namedtuple('monochromator', ['name', 'center', - 'xtal', 'material1', 'material2', 'xtalWidth', 'xtalOffsetX', - 'xtalLength1', 'xtalLength2', 'xtalGap', 'rotOffset', - 'heightOffset', 'braggLim', 'jack1', 'jack2', 'jack3', 'tx']) +monochromator = namedtuple( + "monochromator", + [ + "name", + "center", + "xtal", + "material1", + "material2", + "xtalWidth", + "xtalOffsetX", + "xtalLength1", + "xtalLength2", + "xtalGap", + "rotOffset", + "heightOffset", + "braggLim", + "jack1", + "jack2", + "jack3", + "tx", + ], +) mo1 = monochromator( - name='OP-MO1', - center=[0., 11750, sourceHeight], - xtal=('Si311','Si111'), + name="OP-MO1", + center=[0.0, 11750, sourceHeight], + xtal=("Si311", "Si111"), material1=(si311_1, si111_1), material2=(si311_2, si111_2), - xtalWidth = (24, 24), + xtalWidth=(24, 24), xtalOffsetX=(-21.2, 21.2), - xtalLength1 = (55, 55), - xtalLength2 = (105, 105), - xtalGap = (8, 8), - rotOffset = 6, - heightOffset = 8.5, - braggLim = [3.6, 33], - jack1=[0., 11350., 0.], #Tripod maybe not available! - jack2=[-400., 12350., 0.], - jack3=[400., 12350., 0.], - tx=0.0,) # X-Stage [x] - + xtalLength1=(55, 55), + xtalLength2=(105, 105), + xtalGap=(8, 8), + rotOffset=6, + heightOffset=8.5, + braggLim=[3.6, 33], + jack1=[0.0, 11350.0, 0.0], # Tripod maybe not available! + jack2=[-400.0, 12350.0, 0.0], + jack3=[400.0, 12350.0, 0.0], + tx=0.0, +) # X-Stage [x] + mo2 = monochromator( - name='OP-CCM2', - center=[0., 13250, sourceHeight], - xtal=('Si311','Si111'), + name="OP-CCM2", + center=[0.0, 13250, sourceHeight], + xtal=("Si311", "Si111"), material1=(si311_1, si111_1), material2=(si311_2, si111_2), - xtalWidth = (24, 24), + xtalWidth=(24, 24), xtalOffsetX=(-21, 21), - xtalLength1 = (55, 55), - xtalLength2 = (105, 105), - xtalGap = (8, 8), - rotOffset = 6, - heightOffset = 8.5, - braggLim = [3.6, 33], - jack1=[0., 13350., 0.], #Tripod maybe not available! - jack2=[-400., 14350., 0.], - jack3=[400., 14350., 0.], - tx=0.0,) # X-Stage [x] + xtalLength1=(55, 55), + xtalLength2=(105, 105), + xtalGap=(8, 8), + rotOffset=6, + heightOffset=8.5, + braggLim=[3.6, 33], + jack1=[0.0, 13350.0, 0.0], # Tripod maybe not available! + jack2=[-400.0, 14350.0, 0.0], + jack3=[400.0, 14350.0, 0.0], + tx=0.0, +) # X-Stage [x] # OP Slits -op_slits = namedtuple('op_slits', ['name', 'center']) +op_slits = namedtuple("op_slits", ["name", "center"]) -opSlits1 = op_slits( - name='OP-SLITS 1', - center=(0, 14349.6, sourceHeight), -) +opSlits1 = op_slits(name="OP-SLITS 1", center=(0, 14349.6, sourceHeight)) -opSlits2 = op_slits( - name='OP-SLITS 2', - center=(0, 18134.8, sourceHeight), -) +opSlits2 = op_slits(name="OP-SLITS 2", center=(0, 18134.8, sourceHeight)) # OP Beam Monitors -op_bm = namedtuple('op_bm', ['name', 'center']) +op_bm = namedtuple("op_bm", ["name", "center"]) -opBM1 = op_bm( - name='OP Beam Monitor 1', - center=(0, 14599.6, sourceHeight), +opBM1 = op_bm(name="OP Beam Monitor 1", center=(0, 14599.6, sourceHeight)) + +opBM2 = op_bm(name="OP Beam Monitor 2", center=(0, 18384.8, sourceHeight)) + +# Focusing mirror +focusingMirror = namedtuple( + "focusingMirror", + [ + "name", + "center", + "surfaceToroid", + "materialToroid", + "surfaceFlat", + "materialFlat", + "limPhysXToroid", + "limPhysYToroid", + "limPhysXFlat", + "limPhysYFlat", + "limOptXToroid", + "limOptYToroid", + "limOptXFlat", + "limOptYFlat", + "R", + "pitch", + "r", + "xToroid", + "xFlat", + "hToroid", + "jack1", + "jack2", + "jack3", + "tx1", + "tx2", + ], ) -opBM2 = op_bm( - name='OP Beam Monitor 2', - center=(0, 18384.8, sourceHeight), -) - -# Focusing mirror -focusingMirror = namedtuple('focusingMirror', ['name', 'center', - 'surfaceToroid', 'materialToroid', 'surfaceFlat', 'materialFlat', - 'limPhysXToroid', 'limPhysYToroid', 'limPhysXFlat', 'limPhysYFlat', - 'limOptXToroid', 'limOptYToroid', 'limOptXFlat', 'limOptYFlat', - 'R', 'pitch', 'r', 'xToroid', 'xFlat', 'hToroid', 'jack1', 'jack2', 'jack3', - 'tx1', 'tx2']) - fm = focusingMirror( - name='OP-FM', - center=[0., 15670, sourceHeight], # nominal height 58 mm above ring, SLS1! - surfaceToroid=('Rh', 'Pt'), + name="OP-FM", + center=[0.0, 15670, sourceHeight], # nominal height 58 mm above ring, SLS1! + surfaceToroid=("Rh", "Pt"), materialToroid=(stripeRh, stripePt), - surfaceFlat=('Rh', 'Pt'), + surfaceFlat=("Rh", "Pt"), materialFlat=(stripeRh, stripePt), - limPhysXToroid=(-79., 79.), - limPhysYToroid=(-575., 575.), - limPhysXFlat=(-79., 79.), - limPhysYFlat=(-575., 575.), + limPhysXToroid=(-79.0, 79.0), + limPhysYToroid=(-575.0, 575.0), + limPhysXFlat=(-79.0, 79.0), + limPhysYFlat=(-575.0, 575.0), limOptXToroid=((-38, 66), (-66, 31)), - limOptYToroid=((-500., -500.), (500., 500.)), + limOptYToroid=((-500.0, -500.0), (500.0, 500.0)), limOptXFlat=((-11.45, 23.55), (-30.45, -6.45)), - limOptYFlat=((-500., -500.), (500., 500.)), + limOptYFlat=((-500.0, -500.0), (500.0, 500.0)), R=[3e6, 15e6], pitch=[-5.0e-3, 0e-3], r=[35.510, 24.986], - xToroid=[-52, 48.5], # offset in local x - xFlat = [-20.95, 8.55], - hToroid=[2.88, 7.15], # depth of the cylinder at x = xCylinder1 and x = xCylinder2. - jack1=[-130., 15535-538., 0.], - jack2=[130., 15535+538., 0.], - jack3=[0., 15535+538., 0.], - tx1=[0., -575.], # X-Stage 1 [x, y] - tx2=[0., 575.],) # X-Stage 2 [x, y] + xToroid=[-52, 48.5], # offset in local x + xFlat=[-20.95, 8.55], + hToroid=[2.88, 7.15], # depth of the cylinder at x = xCylinder1 and x = xCylinder2. + jack1=[-130.0, 15535 - 538.0, 0.0], + jack2=[130.0, 15535 + 538.0, 0.0], + jack3=[0.0, 15535 + 538.0, 0.0], + tx1=[0.0, -575.0], # X-Stage 1 [x, y] + tx2=[0.0, 575.0], +) # X-Stage 2 [x, y] # EH Window ehWindow = filt( - name='EH-WINDOW', - center=(0., 19998.3, sourceHeight), - pitch=np.pi/2, - limPhysX=(-20., 20.), + name="EH-WINDOW", + center=(0.0, 19998.3, sourceHeight), + pitch=np.pi / 2, + limPhysX=(-20.0, 20.0), limPhysY=(-4, 4), - surface='None', + surface="None", material=filterSi3N4, - thickness=0.002,) -ehWindow = ehWindow._replace(surface=f'Beryllium window {ehWindow.thickness*1e3:0.0f} $\\mu$m') - + thickness=0.002, +) +ehWindow = ehWindow._replace(surface=f"Beryllium window {ehWindow.thickness*1e3:0.0f} $\\mu$m") + # Sample -sample = namedtuple('sample', ['name', 'center']) +sample = namedtuple("sample", ["name", "center"]) -smpl = sample( - name='EH-SMPL', - center=[0, 23365, sourceHeight],) +smpl = sample(name="EH-SMPL", center=[0, 23365, sourceHeight]) -smpl2 = sample( - name='EH-SMPL2', - center=[0, 27500, sourceHeight],) +smpl2 = sample(name="EH-SMPL2", center=[0, 27500, sourceHeight]) # Vacuum pipes # DN40CF ID = 35 mm oder 37 mm # DN50CF ID = 47.5 mm # DN63CF ID = 60.2 mm oder 66 mm # DN100CF ID = 97.4 mm oder 104 mm -pipe = namedtuple('pipes', ['center', 'diameter', 'start', 'end']) +pipe = namedtuple("pipes", ["center", "diameter", "start", "end"]) vacuum_pipes = pipe( - center= [27.5, (37.5+27.5)/2, 37.5, 62.5, 72.5], - diameter=[97.4, 97.4, 97.4, 97.4, 97.4], - start= [10952.88, 11750+250, mo2.center[1]+250, 14000, fm.center[1]], - end= [11750-250, mo2.center[1]-250, 14000, fm.center[1], ehWindow.center[1]], + center=[27.5, (37.5 + 27.5) / 2, 37.5, 62.5, 72.5], + diameter=[97.4, 97.4, 97.4, 97.4, 97.4], + start=[10952.88, 11750 + 250, mo2.center[1] + 250, 14000, fm.center[1]], + end=[11750 - 250, mo2.center[1] - 250, 14000, fm.center[1], ehWindow.center[1]], ) -Walls = namedtuple('walls', ['start', 'end', 'height']) -walls = Walls( - start= [13999.30], - end= [13999+75.5+30], - height= [[-20, 25]], -) +Walls = namedtuple("walls", ["start", "end", "height"]) +walls = Walls(start=[13999.30], end=[13999 + 75.5 + 30], height=[[-20, 25]])