Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Mirrors, Slits, and Tables. #151

Merged
merged 17 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
77f61bc
Added configurable motors to the KB mirror device definition.
canismarko Dec 8, 2023
cf6512e
Enable bender controls for KB mirrors window.
canismarko Dec 10, 2023
7aa2fa2
Removed the 'mirrors' label from the individual mirrors of a KBMirror…
canismarko Dec 10, 2023
036cf96
Motors already assigned to a device (i.e. KB mirrors) are now not inc…
canismarko Dec 11, 2023
861c173
Bug fix where all KB mirrors were considered bendable.
canismarko Dec 11, 2023
bcf39e7
Tweaks to the mirror devices/windows at the beamline.
Dec 11, 2023
c12e97a
Added KB mirror benders to the caQtDM macros.
canismarko Dec 12, 2023
48085f0
Cleaned up the mirror caQtDM handling at the beamline.
Dec 12, 2023
6ff0483
Moved motor co-routines to a separate asyncio.gather(), so they skip …
Dec 12, 2023
b6677b2
Added real motors to the Aperture slits.
canismarko Dec 13, 2023
35d4856
Added a dynamic device class for the tables at sector 25.
canismarko Dec 14, 2023
58c736c
Added a (non-functional) firefly display for the Table device.
canismarko Dec 14, 2023
77cfc8a
Added device loading functions for the tables: load_tables().
canismarko Dec 15, 2023
fdf36a7
Re-factored the Table class to use a more sensible PV name structure.
canismarko Dec 16, 2023
f9a571b
Table window now auto-disables unused motors, and added table actions…
canismarko Dec 16, 2023
e99dded
Cleaned up the table window at the beamline. Also added icons to the …
Dec 16, 2023
d565728
caQtDM support for optical tables.
canismarko Dec 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ dependencies:
# --- Qt
# Pin at 5.12.3 until pydm figures out how to designer widgets
- pyqt ==5.12.3
- pyqtgraph < 0.13.0 # Last version to support pyqt 5.12
# - pyqt >=5.12, <5.13
- qt >=5.12
- qtawesome
- pyqtgraph

# --- general support packages
- bitshuffle
Expand Down
8 changes: 5 additions & 3 deletions src/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,11 @@ def blade_slits(sim_registry):
def aperture_slits(sim_registry):
"""A fake slit assembling using the rotary aperture design."""
FakeSlits = make_fake_device(ApertureSlits)
slits = FakeSlits(
prefix="255ida:slits:US:", name="whitebeam_slits", labels={"slits"}
)
slits = FakeSlits( prefix="255ida:slits:US:",
name="whitebeam_slits", pitch_motor="m3",
yaw_motor="m4",
horizontal_motor="m1",
diagonal_motor="m2", labels={"slits"})
sim_registry.register(slits)
return slits

Expand Down
18 changes: 16 additions & 2 deletions src/firefly/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def setup_window_actions(self):
"""
# Setup actions for the various categories of devices
self._prepare_device_windows(
device_label="motors",
device_label="extra_motors",
attr_name="motor",
ui_file="motor.py",
device_key="MOTOR",
Expand Down Expand Up @@ -178,18 +178,28 @@ def setup_window_actions(self):
attr_name="slits",
ui_file="slits.py",
device_key="DEVICE",
icon=qta.icon("mdi.crop"),
)
self._prepare_device_windows(
device_label="kb_mirrors",
attr_name="kb_mirrors",
ui_file="kb_mirrors.py",
device_key="DEVICE",
icon=qta.icon("msc.mirror"),
)
self._prepare_device_windows(
device_label="mirrors",
attr_name="mirror",
ui_file="mirror.py",
device_key="DEVICE",
icon=qta.icon("msc.mirror"),
)
self._prepare_device_windows(
device_label="tables",
attr_name="table",
ui_file="table.py",
device_key="DEVICE",
icon=qta.icon("mdi.table-furniture"),
)
self._prepare_device_windows(
device_label="xrf_detectors",
Expand Down Expand Up @@ -314,6 +324,7 @@ def _prepare_device_windows(
ui_file=None,
window_slot=None,
device_key="DEVICE",
icon=None,
):
"""Generic routine to be called for individual classes of devices.

Expand Down Expand Up @@ -346,7 +357,8 @@ def _prepare_device_windows(
dictionary. If *device_key* is "DEVICE" (default), then the
macros will be {"DEVICE": device.name}. Has no effect if
*window_slot* is used.

icon
A QIcon that will be added to the action.
"""
# We need a UI file, unless a custom window_slot is given
if ui_file is None and window_slot is None:
Expand All @@ -371,6 +383,8 @@ def _prepare_device_windows(
action.setObjectName(f"action_show_{attr_name}_{device.name}")
display_text = titelize(device.name)
action.setText(display_text)
if icon is not None:
action.setIcon(icon)
actions[device.name] = action
# Create a slot for opening the device window
if window_slot is not None:
Expand Down
37,678 changes: 20,304 additions & 17,374 deletions src/firefly/beamline_components_rc.py

Large diffs are not rendered by default.

76 changes: 71 additions & 5 deletions src/firefly/kb_mirrors.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,28 @@


class KBMirrorsDisplay(SlitsDisplay):
caqtdm_ui_filenames = {
mirrors.KBMirrors: "/net/s25data/xorApps/ui/KB_mirrors.ui",
}

@property
def caqtdm_ui_file(self):
# Go up the class list until we find a class that is recognized
if self.device.horiz.bendable or self.device.vert.bendable:
ui_file = "/net/s25data/xorApps/ui/KB_mirrors_and_benders.ui"
else:
ui_file = "/net/s25data/xorApps/ui/KB_mirrors.ui"
return ui_file

def ui_filename(self):
return "kb_mirrors.ui"

def customize_ui(self):
# Enable/disable bender controls
horiz = self.device.horiz
self.ui.horizontal_upstream_display.setEnabled(horiz.bendable)
self.ui.horizontal_downstream_display.setEnabled(horiz.bendable)
vert = self.device.vert
self.ui.vertical_upstream_display.setEnabled(vert.bendable)
self.ui.vertical_downstream_display.setEnabled(vert.bendable)

def launch_caqtdm(self):
# Sort out the prefix from the slit designator
prefix = self.device.prefix.strip(":")
Expand All @@ -20,13 +35,64 @@ def launch_caqtdm(self):
P = ":".join(pieces[:-1])
P = f"{P}:"
KB = pieces[-1]
KBH = self.device.horiz.prefix.replace(P, "")
KBV = self.device.vert.prefix.replace(P, "")
KBH = self.device.horiz.prefix.replace(P, "").strip(":")
KBV = self.device.vert.prefix.replace(P, "").strip(":")
def suffix(signal):
return signal.prefix.split(":")[-1]

caqtdm_macros = {
"P": f"{P}",
"PM": P,
"KB": KB,
"KBH": KBH,
"KBV": KBV,
# Macros for the real motors
"KBHUS": suffix(self.device.horiz.upstream),
"KBHDS": suffix(self.device.horiz.downstream),
"KBVUS": suffix(self.device.vert.upstream),
"KBVDS": suffix(self.device.vert.downstream),
# Macros for the transform records
"KB1": KBH.replace(":", ""),
"KB2": KBV.replace(":", ""),
}
# Macros for each mirror's bender motors
horiz = self.device.horiz
if horiz.bendable:
caqtdm_macros.update({
"HBUS": suffix(horiz.bender_upstream),
"HBDS": suffix(horiz.bender_downstream),
})
vert = self.device.vert
if vert.bendable:
caqtdm_macros.update({
"VBUS": suffix(vert.bender_upstream),
"VBDS": suffix(vert.bender_downstream),
})
# Launch the caQtDM panel
super(SlitsDisplay, self).launch_caqtdm(macros=caqtdm_macros)


# -----------------------------------------------------------------------------
# :author: Mark Wolfman
# :email: [email protected]
# :copyright: Copyright © 2023, UChicago Argonne, LLC
#
# Distributed under the terms of the 3-Clause BSD License
#
# The full license is in the file LICENSE, distributed with this software.
#
# DISCLAIMER
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# -----------------------------------------------------------------------------
55 changes: 41 additions & 14 deletions src/firefly/kb_mirrors.ui
Original file line number Diff line number Diff line change
Expand Up @@ -566,21 +566,21 @@
<zorder>label_3</zorder>
<zorder>label_2</zorder>
<zorder>vertical_pitch_polyline</zorder>
<zorder>vertical_normal_display</zorder>
<zorder>horizontal_pitch_display</zorder>
<zorder>vertical_pitch_arc</zorder>
<zorder>horizontal_pitch_arc</zorder>
<zorder>hoizontal_pitch_polyline</zorder>
<zorder>horizontal_normal_display</zorder>
<zorder>vertical_pitch_display</zorder>
<zorder>PyDMDrawingLine_4</zorder>
<zorder>PyDMDrawingLine_5</zorder>
<zorder>PyDMDrawingPolyline_2</zorder>
<zorder>PyDMDrawingLine_6</zorder>
<zorder>vertical_pitch_display</zorder>
<zorder>horizontal_pitch_display</zorder>
<zorder>vertical_normal_display</zorder>
<zorder>horizontal_normal_display</zorder>
</widget>
<widget class="QWidget" name="benders_tab">
<property name="enabled">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="styleSheet">
<string notr="true"/>
Expand Down Expand Up @@ -648,12 +648,15 @@
</property>
</widget>
<widget class="PyDMEmbeddedDisplay" name="vertical_upstream_display">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>430</x>
<y>90</y>
<y>79</y>
<width>101</width>
<height>100</height>
<height>111</height>
</rect>
</property>
<property name="font">
Expand All @@ -668,7 +671,7 @@
<enum>QFrame::NoFrame</enum>
</property>
<property name="macros" stdset="0">
<string>{&quot;TITLE&quot;: &quot;Upstream&quot;}</string>
<string>TITLE=Upstream,AXIS=${DEVICE}.vert.bender_upstream</string>
</property>
<property name="filename" stdset="0">
<string>slits_motor.py</string>
Expand All @@ -684,12 +687,15 @@
</property>
</widget>
<widget class="PyDMEmbeddedDisplay" name="horizontal_downstream_display">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>18</x>
<y>150</y>
<width>101</width>
<height>100</height>
<height>111</height>
</rect>
</property>
<property name="font">
Expand All @@ -709,7 +715,7 @@ color: white;
<enum>QFrame::NoFrame</enum>
</property>
<property name="macros" stdset="0">
<string>{&quot;TITLE&quot;: &quot;Downstream&quot;}</string>
<string>TITLE=Downstream,AXIS=${DEVICE}.horiz.bender_downstream</string>
</property>
<property name="filename" stdset="0">
<string>slits_motor.py</string>
Expand All @@ -725,12 +731,15 @@ color: white;
</property>
</widget>
<widget class="PyDMEmbeddedDisplay" name="horizontal_upstream_display">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>230</x>
<y>0</y>
<width>101</width>
<height>100</height>
<height>111</height>
</rect>
</property>
<property name="font">
Expand All @@ -745,7 +754,7 @@ color: white;
<enum>QFrame::NoFrame</enum>
</property>
<property name="macros" stdset="0">
<string>{&quot;TITLE&quot;: &quot;Upstream&quot;}</string>
<string>TITLE=Upstream,AXIS=${DEVICE}.horiz.bender_upstream</string>
</property>
<property name="filename" stdset="0">
<string>slits_motor.py</string>
Expand All @@ -761,12 +770,15 @@ color: white;
</property>
</widget>
<widget class="PyDMEmbeddedDisplay" name="vertical_downstream_display">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>157</x>
<y>260</y>
<width>101</width>
<height>100</height>
<height>111</height>
</rect>
</property>
<property name="font">
Expand All @@ -781,7 +793,7 @@ color: white;
<enum>QFrame::NoFrame</enum>
</property>
<property name="macros" stdset="0">
<string>{&quot;TITLE&quot;: &quot;Downstream&quot;}</string>
<string>TITLE=Downstream,AXIS=${DEVICE}.vert.bender_downstream</string>
</property>
<property name="filename" stdset="0">
<string>slits_motor.py</string>
Expand Down Expand Up @@ -1032,6 +1044,21 @@ color: white;
<double>90.000000000000000</double>
</property>
</widget>
<zorder>label_4</zorder>
<zorder>label_5</zorder>
<zorder>label_6</zorder>
<zorder>vertical_downstream_arc</zorder>
<zorder>vertical_downstream_arc_2</zorder>
<zorder>vertical_downstream_arc_3</zorder>
<zorder>vertical_downstream_arc_4</zorder>
<zorder>PyDMDrawingLine</zorder>
<zorder>PyDMDrawingLine_2</zorder>
<zorder>PyDMDrawingPolyline</zorder>
<zorder>PyDMDrawingLine_3</zorder>
<zorder>vertical_upstream_display</zorder>
<zorder>vertical_downstream_display</zorder>
<zorder>horizontal_upstream_display</zorder>
<zorder>horizontal_downstream_display</zorder>
</widget>
</widget>
</widget>
Expand Down
14 changes: 9 additions & 5 deletions src/firefly/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@

from pydm import data_plugins
from pydm.main_window import PyDMMainWindow

# from qtpy.QtCore import Slot
from qtpy import QtCore, QtGui, QtWidgets
import qtawesome as qta

from haven import load_config

Expand Down Expand Up @@ -40,6 +39,7 @@ def open(self, *args, **kwargs):
if len(caqtdm_actions) > 0:
caqtdm_menu.addSeparator()
for action in caqtdm_actions:
action.setIcon(qta.icon("fa5s.wrench"))
caqtdm_menu.addAction(action)

def closeEvent(self, event):
Expand Down Expand Up @@ -140,18 +140,22 @@ def customize_ui(self):
# Motors sub-menu
self.ui.menuMotors = QtWidgets.QMenu(self.ui.menubar)
self.ui.menuMotors.setObjectName("menuMotors")
self.ui.menuMotors.setTitle("Motors")
self.ui.menuMotors.setTitle("Extra &Motors")
self.ui.positioners_menu.addAction(self.ui.menuMotors.menuAction())
# Menu to launch the Window to change energy
self.ui.positioners_menu.addAction(app.show_energy_window_action)
# Add optical components
self.ui.positioners_menu.addSeparator()
self.ui.positioners_menu.addSection("Slits")
for action in app.slits_actions.values():
self.ui.positioners_menu.addAction(action)
self.ui.positioners_menu.addSection("Mirrors")
for action in app.kb_mirrors_actions.values():
self.ui.positioners_menu.addAction(action)
for action in app.mirror_actions.values():
self.ui.positioners_menu.addAction(action)
self.ui.positioners_menu.addAction(action)
self.ui.positioners_menu.addSection("Tables")
for action in app.table_actions.values():
self.ui.positioners_menu.addAction(action)
# Scans menu
self.ui.menuScans = QtWidgets.QMenu(self.ui.menubar)
self.ui.menuScans.setObjectName("menuScans")
Expand Down
Loading