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 XIA PFCU filters #203

Merged
merged 24 commits into from
Apr 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d3ad10f
Added a device for PFCU-based filters.
canismarko Apr 14, 2024
fa70fff
Allow some PFCU filter channels to be turned into shutters.
canismarko Apr 14, 2024
6c37016
The PFCU4Shutter device can now be opened and closed.
canismarko Apr 17, 2024
58693e5
Fixed wrong prefix for PFCU4 shutter filter.
yannachen Apr 18, 2024
cdc1fb6
Added a function to load the XIA PFCU4 filter banks.
canismarko Apr 19, 2024
46dac9b
Used the PVPositionerSoftDone for the PFCU filters.
yannachen Apr 20, 2024
95dea0f
Fixed broken xia PFCU4 shutter tests.
canismarko Apr 20, 2024
ff3e244
Added a firefly window for showing filters.
canismarko Apr 22, 2024
d408fa4
Improved the UI for the filters in Firefly.
yannachen Apr 22, 2024
2e8aa8f
The XIA PFCU shutter device now uses the entire filter bank configura…
canismarko Apr 24, 2024
4127327
Made the graphic for the filters window look continuous (removed padd…
yannachen Apr 24, 2024
ebf031f
Fixed polarity of XIA PFCU-based shutter.
yannachen Apr 24, 2024
3e567c0
Fixed PFCU filter tests.
canismarko Apr 24, 2024
99c814c
The Firefly status window now dynamically creates shutter widgets.
canismarko Apr 25, 2024
1903866
Added a get() method to the Xia Shutter device.
yannachen Apr 26, 2024
ebfcd79
The XIA PFCUShutter now has a readback signal with the shutter's curr…
canismarko Apr 26, 2024
956aa5c
Added is_open and is_closed signals to the XIA PFCUShutter device.
canismarko Apr 26, 2024
4abc942
Partially implemented the shutter widgets in the status window.
yannachen Apr 26, 2024
4a96cc6
Made the XIA PFCUShutter into a proper Ophyd positioner.
canismarko Apr 28, 2024
328afa3
The XIA PFCUFilterBank now uses PFCUFastShutters by default.
yannachen Apr 28, 2024
ed7254a
Fixed XIA tests, removed old code, and linted.
canismarko Apr 28, 2024
c40ef97
Changed the XIA PFCUShutter states enum when the shutter is half-open.
yannachen Apr 28, 2024
bf45440
Fixed broken test in firefly filter.
canismarko Apr 28, 2024
26ed28e
Added copyright notices to new files.
canismarko Apr 28, 2024
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
52 changes: 48 additions & 4 deletions src/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# from pydm.data_plugins import plugin_modules, add_plugin
import pytest
from apstools.devices.srs570_preamplifier import GainSignal
from ophyd import DynamicDeviceComponent as DDC
from ophyd import DynamicDeviceComponent as DCpt
from ophyd import Kind
from ophyd.sim import (
FakeEpicsSignal,
Expand Down Expand Up @@ -36,6 +36,7 @@
from haven.instrument.robot import Robot
from haven.instrument.shutter import Shutter
from haven.instrument.slits import ApertureSlits, BladeSlits
from haven.instrument.xia_pfcu import PFCUFilter, PFCUFilterBank, PFCUShutter
from haven.instrument.xspress import Xspress3Detector
from haven.instrument.xspress import add_mcas as add_xspress_mcas

Expand Down Expand Up @@ -161,7 +162,7 @@ class SimpleBeamlineManager(BeamlineManager):

"""

iocs = DDC(
iocs = DCpt(
{
"ioc255idb": (IOCManager, "ioc255idb:", {}),
"ioc255idc": (IOCManager, "ioc255idc:", {}),
Expand Down Expand Up @@ -211,7 +212,7 @@ def sim_camera(sim_registry):


class DxpVortex(DxpDetector):
mcas = DDC(
mcas = DCpt(
add_dxp_mcas(range_=[0, 1, 2, 3]),
kind=Kind.normal | Kind.hinted,
default_read_attrs=[f"mca{i}" for i in [0, 1, 2, 3]],
Expand All @@ -229,7 +230,7 @@ def dxp(sim_registry):


class Xspress3Vortex(Xspress3Detector):
mcas = DDC(
mcas = DCpt(
add_xspress_mcas(range_=[0, 1, 2, 3]),
kind=Kind.normal | Kind.hinted,
default_read_attrs=[f"mca{i}" for i in [0, 1, 2, 3]],
Expand Down Expand Up @@ -289,6 +290,33 @@ def aps(sim_registry):
yield aps


@pytest.fixture()
def xia_shutter_bank(sim_registry):
class ShutterBank(PFCUFilterBank):
shutters = DCpt(
{
"shutter_0": (
PFCUShutter,
"",
{"top_filter": 4, "bottom_filter": 3, "labels": {"shutters"}},
)
}
)

def __new__(cls, *args, **kwargs):
return object.__new__(cls)

FakeBank = make_fake_device(ShutterBank)
bank = FakeBank(prefix="255id:pfcu4:", name="xia_filter_bank", shutters=[[3, 4]])
sim_registry.register(bank)
yield bank


@pytest.fixture()
def xia_shutter(xia_shutter_bank):
yield xia_shutter_bank.shutters.shutter_0


@pytest.fixture()
def shutters(sim_registry):
FakeShutter = make_fake_device(Shutter)
Expand All @@ -309,6 +337,22 @@ def shutters(sim_registry):
yield shutters


@pytest.fixture()
def filters(sim_registry):
FakeFilter = make_fake_device(PFCUFilter)
kw = {
"labels": {"filters"},
}
filters = [
FakeFilter(name="Filter A", prefix="filter1", **kw),
FakeFilter(name="Filter B", prefix="filter2", **kw),
]
# Register the simulated filters
for fltr in filters:
sim_registry.register(fltr)
return filters


# holds a global QApplication instance created in the qapp fixture; keeping
# this reference alive avoids it being garbage collected too early
_ffapp_instance = None
Expand Down
13 changes: 13 additions & 0 deletions src/firefly/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,12 @@ def setup_window_actions(self):
ui_file="xrf_detector.py",
device_key="DEV",
)
self._setup_window_action(
action_name="show_filters_window_action",
text="Filters",
slot=self.show_filters_window,
)
self.show_filters_window_action.setIcon(qta.icon("mdi.air-filter"))
# Action for showing the beamline status window
self._setup_window_action(
action_name="show_status_window_action",
Expand Down Expand Up @@ -254,6 +260,7 @@ def setup_window_actions(self):
text="Energy",
slot=self.show_energy_window,
)
self.show_energy_window_action.setIcon(qta.icon("mdi.sine-wave"))
# Launch camera overview
self._setup_window_action(
action_name="show_cameras_window_action",
Expand Down Expand Up @@ -643,6 +650,12 @@ def show_bss_window(self):
def show_iocs_window(self):
return self.show_window(FireflyMainWindow, ui_dir / "iocs.py", name="iocs")

@QtCore.Slot()
def show_filters_window(self):
return self.show_window(
FireflyMainWindow, ui_dir / "filters.py", name="filters"
)

@QtCore.Slot(bool)
def set_open_environment_action_state(self, is_open: bool):
"""Update the readback value for opening the queueserver environment."""
Expand Down
5,524 changes: 5,504 additions & 20 deletions src/firefly/beamline_components_rc.py

Large diffs are not rendered by default.

35 changes: 35 additions & 0 deletions src/firefly/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import json
from typing import Sequence

from pydm.widgets import PyDMEmbeddedDisplay

from firefly import display
from haven import registry


class FiltersDisplay(display.FireflyDisplay):
filters: Sequence

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

def customize_device(self):
filters = registry.findall(label="filters", allow_none=True)
self.filters = sorted(
filters, key=lambda dev: (dev.material.get(), dev.thickness.get())
)

def customize_ui(self):
# Delete existing filter widgets
for idx in reversed(range(self.filters_layout.count())):
self.filters_layout.takeAt(idx).widget().deleteLater()
# Add embedded displays for all the ion chambers
self._filter_displays = []
for idx, device in enumerate(self.filters):
# Create the display object
disp = PyDMEmbeddedDisplay(parent=self)
disp.macros = json.dumps({"DEV": device.name})
disp.filename = "filters_row.ui"
# Add the Embedded Display to the Results Layout
self.filters_layout.addWidget(disp)
self._filter_displays.append(disp)
89 changes: 89 additions & 0 deletions src/firefly/filters.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>598</width>
<height>376</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="filters_layout">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="PyDMEmbeddedDisplay" name="PyDMEmbeddedDisplay_2">
<property name="toolTip">
<string/>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="filename" stdset="0">
<string>filters_row.ui</string>
</property>
</widget>
</item>
<item>
<widget class="PyDMEmbeddedDisplay" name="PyDMEmbeddedDisplay">
<property name="toolTip">
<string/>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="filename" stdset="0">
<string>filters_row.ui</string>
</property>
</widget>
</item>
<item>
<widget class="PyDMEmbeddedDisplay" name="PyDMEmbeddedDisplay_3">
<property name="toolTip">
<string/>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="filename" stdset="0">
<string>filters_row.ui</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>PyDMEmbeddedDisplay</class>
<extends>QFrame</extends>
<header>pydm.widgets.embedded_display</header>
</customwidget>
</customwidgets>
<resources>
<include location="resources/beamline_components.qrc"/>
</resources>
<connections/>
</ui>
Loading