feat: live energy/wavelength readout in Beamline setup
New 'Current energy / lambda' row above the setpoint, fed per DAQ tick from diffraction.energy_keV; the setpoint row is renamed 'Set Energy (keV)' so 'what is' and 'what to set' are distinct. Guards energy 0.0 (server's detector-unavailable fallback) because the wavelength property divides by it. The copied energy row in the experiment configuration is renamed to match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -97,7 +97,7 @@ class DataCollectionSettings(QFrame):
|
||||
energy_row = QWidget(self)
|
||||
energy_layout = QHBoxLayout(energy_row)
|
||||
energy_layout.setContentsMargins(0, 0, 0, 0)
|
||||
energy_layout.addWidget(QLabel("Energy (keV)", parent=energy_row))
|
||||
energy_layout.addWidget(QLabel("Set Energy (keV)", parent=energy_row))
|
||||
energy_layout.addWidget(self.energy_spin)
|
||||
energy_layout.addWidget(self.change_energy_button)
|
||||
|
||||
|
||||
@@ -26,22 +26,28 @@ class MonochromatorPanel(QWidget):
|
||||
self.mono_pitch_scan_button.clicked.connect(self.mono_pitch_scan.emit)
|
||||
grid_layout.addWidget(self.mono_pitch_scan_button, 1, 0, 1, 3)
|
||||
|
||||
# Live readout above the setpoint, so "what is" and "what to set"
|
||||
# stop sharing one ambiguous Energy row. Fed per DAQ tick.
|
||||
grid_layout.addWidget(QLabel("Current energy / λ", parent=self), 2, 0)
|
||||
self.current_energy_label = QLabel("—", parent=self)
|
||||
grid_layout.addWidget(self.current_energy_label, 2, 1, 1, 2)
|
||||
|
||||
# One row (label | value | button) instead of three — vertical space.
|
||||
# Display in keV; the DAQ API stays in eV (converted on emit).
|
||||
# Unit lives in the label, not as a spinbox suffix — the suffix ate
|
||||
# field width and sat between the value and the +/- arrow.
|
||||
grid_layout.addWidget(QLabel("Energy (keV)", parent=self), 2, 0)
|
||||
grid_layout.addWidget(QLabel("Set Energy (keV)", parent=self), 3, 0)
|
||||
|
||||
self.energy_spin = QDoubleSpinBox(parent=self)
|
||||
self.energy_spin.setDecimals(3)
|
||||
self.energy_spin.setRange(1.0, 30.0)
|
||||
self.energy_spin.setSingleStep(0.1)
|
||||
self.energy_spin.setValue(12.0)
|
||||
grid_layout.addWidget(self.energy_spin, 2, 1)
|
||||
grid_layout.addWidget(self.energy_spin, 3, 1)
|
||||
|
||||
self.change_energy_button = QPushButton("Change Energy", parent=self)
|
||||
self.change_energy_button.clicked.connect(self._emit_change_energy)
|
||||
grid_layout.addWidget(self.change_energy_button, 2, 2)
|
||||
grid_layout.addWidget(self.change_energy_button, 3, 2)
|
||||
|
||||
# TODO(wire backend): no DAQ endpoint exists yet for moving the beam
|
||||
# to the box center — shown disabled as WIP until the operation is
|
||||
@@ -51,12 +57,21 @@ class MonochromatorPanel(QWidget):
|
||||
self.move_beam_to_box_button.setToolTip("Coming soon — not functional yet.")
|
||||
self.move_beam_to_box_button.setEnabled(False)
|
||||
self.move_beam_to_box_button.clicked.connect(self.move_beam_to_box.emit)
|
||||
grid_layout.addWidget(self.move_beam_to_box_button, 3, 0, 1, 3)
|
||||
grid_layout.addWidget(self.move_beam_to_box_button, 4, 0, 1, 3)
|
||||
|
||||
@Slot()
|
||||
def _emit_change_energy(self):
|
||||
self.change_energy.emit(float(self.energy_spin.value()) * 1000.0)
|
||||
|
||||
@Slot(DAQStatusModel)
|
||||
def update_daq_status(self, _status: DAQStatusModel):
|
||||
pass
|
||||
def update_daq_status(self, status: DAQStatusModel):
|
||||
energy = status.diffraction.energy_keV
|
||||
# 0.0 is the server's detector-unavailable fallback, and the
|
||||
# wavelength property divides by it — guard before touching it.
|
||||
if not energy:
|
||||
text = "— / —"
|
||||
else:
|
||||
text = f"{energy:.3f} keV / {status.diffraction.wavelength_angstrom:.4f} Å"
|
||||
# Guarded: runs per DAQ tick (2 Hz), skip the repaint when unchanged.
|
||||
if self.current_energy_label.text() != text:
|
||||
self.current_energy_label.setText(text)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
from aare.gui.panels.monochromator_panel import MonochromatorPanel
|
||||
|
||||
|
||||
def test_current_energy_readout(qtbot, daq_status_factory):
|
||||
panel = MonochromatorPanel()
|
||||
qtbot.addWidget(panel)
|
||||
|
||||
status = daq_status_factory()
|
||||
panel.update_daq_status(status)
|
||||
assert panel.current_energy_label.text() == "12.000 keV / 1.0332 Å"
|
||||
|
||||
# 0.0 is the server's detector-unavailable fallback; the wavelength
|
||||
# property divides by energy, so the readout must not touch it.
|
||||
status.diffraction = status.diffraction.model_copy(update={"energy_keV": 0.0})
|
||||
panel.update_daq_status(status)
|
||||
assert panel.current_energy_label.text() == "— / —"
|
||||
Reference in New Issue
Block a user