-
Notifications
You must be signed in to change notification settings - Fork 12
ElectronAnalyser no longer depends directly on sequence file path to work with BlueAPI #1923
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
base: main
Are you sure you want to change the base?
Changes from all commits
59d30c8
7d4d359
3075079
9c2887e
d87a608
7a97a23
de1c820
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| from .b07_motors import B07SampleManipulator52B | ||
| from .enums import Grating, LensMode, PsuMode | ||
| from .enums import Grating, LensMode | ||
|
|
||
| __all__ = ["B07SampleManipulator52B", "Grating", "LensMode", "PsuMode"] | ||
| __all__ = ["B07SampleManipulator52B", "Grating", "LensMode"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| from .enums import PsuMode | ||
|
|
||
| __all__ = ["PsuMode"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| from ophyd_async.core import SupersetEnum | ||
|
|
||
|
|
||
| class PsuMode(SupersetEnum): | ||
| V3500 = "3.5kV" | ||
| V1500 = "1.5kV" | ||
| V400 = "400V" | ||
| V100 = "100V" | ||
| V10 = "10V" | ||
| # This is connected to the device separately and will only have "Not connected" as | ||
| # option if disconnected. Once it is connected, "Not connected" is replaced with the | ||
| # options above. This is also why this must be a SupersetEnum. | ||
| NOT_CONNECTED = "Not connected" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,7 +10,6 @@ | |
| TriggerInfo, | ||
| ) | ||
|
|
||
| from dodal.common.data_util import load_json_file_to_class | ||
| from dodal.devices.electron_analyser.base.base_controller import ( | ||
| ElectronAnalyserController, | ||
| ) | ||
|
|
@@ -20,9 +19,7 @@ | |
| ) | ||
| from dodal.devices.electron_analyser.base.base_region import ( | ||
| GenericRegion, | ||
| GenericSequence, | ||
| TAbstractBaseRegion, | ||
| TAbstractBaseSequence, | ||
| ) | ||
|
|
||
|
|
||
|
|
@@ -111,6 +108,9 @@ async def trigger(self) -> None: | |
| await super().trigger() | ||
|
|
||
|
|
||
| # Used in sm-bluesky, but will hopefully be removed along with | ||
| # ElectronAnalyserRegionDetector in future. Blocked by: | ||
| # https://github.com/bluesky/bluesky/pull/1978 | ||
| GenericElectronAnalyserRegionDetector = ElectronAnalyserRegionDetector[ | ||
| GenericAnalyserDriverIO, GenericRegion | ||
| ] | ||
|
|
@@ -123,7 +123,7 @@ async def trigger(self) -> None: | |
| class ElectronAnalyserDetector( | ||
| BaseElectronAnalyserDetector[TAbstractAnalyserDriverIO, TAbstractBaseRegion], | ||
| Stageable, | ||
| Generic[TAbstractBaseSequence, TAbstractAnalyserDriverIO, TAbstractBaseRegion], | ||
Villtord marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Generic[TAbstractAnalyserDriverIO, TAbstractBaseRegion], | ||
| ): | ||
| """Electron analyser detector with the additional functionality to load a sequence | ||
| file and create a list of temporary ElectronAnalyserRegionDetector objects. These | ||
|
|
@@ -132,13 +132,13 @@ class ElectronAnalyserDetector( | |
|
|
||
| def __init__( | ||
| self, | ||
| sequence_class: type[TAbstractBaseSequence], | ||
| controller: ElectronAnalyserController[ | ||
| TAbstractAnalyserDriverIO, TAbstractBaseRegion | ||
| ], | ||
| name: str = "", | ||
| ): | ||
| self._sequence_class = sequence_class | ||
| # Save on device so connect works and names it as child | ||
| self.driver = controller.driver | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is a driver that is created and passed in a child class, here in parent class it is taken out from the controller and saved as a class object - wouldn't it be clearer to make it in a child class directly when driver is created?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The class is then in charge of making sure the driver and detector connect and parent/name relationship is correct rather than the API. It's much better to make sure the API does it as all classes will need to do this, otherwise we copy and paste this line x number times for number of implementations which is unnecessary.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you probably won't need to copy paste anything just add "self.driver" instead of making internal "driver" in a child class
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The issue with this is that if we type anything as using the GenericElectronAnalyser for tests or plans or other devices i.e it doesn't care about if it Specs, Mbs, VGScienta etc. then it loses access to the driver because it lives now on the implementation and not on the base. We need it to be done here.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it looks like your use case for this is only relevant for tests, you probably could in analyser-related plan specify a parameter as GenericElectronAnalyser in a plan but you anyway want to operate using verbs so Movable, Readable or StandardDetector class (when it's there) would suffice? Isn't it the whole point of this change to get rid of generic analyser, am I missing smth?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. or are you planning to call
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the Bluesky change goes through with allowing devices have multiple configuration, then we can remove method
and that isn't including the PsuMode, PassEnergy and LensMode types. I think the reason they aren't used in the plans themselves is because they are invariant so has a couple of issues, but again this isn't related to this change. Plans can still have full typing of the device and would need it to access child devices e.g E.g def my_plan(my_device: Movable):
yield from mv(my_device.child_device1, 2) #invalid type checking
yield from mv(my_device.child_device2, 5) #invalid type checkingIf you give the correct type for the plan static type checking won't complain. If you dislike the generics classes because they are only used in tests and not plans at the moment we can address this in a new issue/PR.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I rather dislike that inverse logic of having driver in base class via controller in child class that actually creates that driver -> which seems to be justified only for having GenericElectronAnalyser device having access to driver which is used only in tests and plan tests. |
||
| super().__init__(controller, name) | ||
|
|
||
| @AsyncStatus.wrap | ||
|
|
@@ -160,38 +160,24 @@ async def unstage(self) -> None: | |
| """Disarm the detector.""" | ||
| await self._controller.disarm() | ||
|
|
||
| def load_sequence(self, filename: str) -> TAbstractBaseSequence: | ||
| """Load the sequence data from a provided json file into a sequence class. | ||
| Args: | ||
| filename (str): Path to the sequence file containing the region data. | ||
| Returns: | ||
| Pydantic model representing the sequence file. | ||
| """ | ||
| return load_json_file_to_class(self._sequence_class, filename) | ||
|
|
||
| def create_region_detector_list( | ||
| self, filename: str, enabled_only=True | ||
| self, regions: list[TAbstractBaseRegion] | ||
| ) -> list[ | ||
| ElectronAnalyserRegionDetector[TAbstractAnalyserDriverIO, TAbstractBaseRegion] | ||
| ]: | ||
| """Create a list of detectors equal to the number of regions in a sequence file. | ||
| Each detector is responsible for setting up a specific region. | ||
| """This method can hopefully be dropped when this is merged and released. | ||
| https://github.com/bluesky/bluesky/pull/1978. | ||
| Create a list of detectors equal to the number of regions. Each detector is | ||
| responsible for setting up a specific region. | ||
| Args: | ||
| filename (str): Path to the sequence file containing the region data. | ||
| enabled_only (bool, optional): If true, only include the region if enabled | ||
| is True. | ||
| regions: The list of regions to give to each region detector. | ||
| Returns: | ||
| List of ElectronAnalyserRegionDetector, equal to the number of regions in | ||
| the sequence file. | ||
| the sequence file. | ||
| """ | ||
| seq = self.load_sequence(filename) | ||
| regions: list[TAbstractBaseRegion] = ( | ||
| seq.get_enabled_regions() if enabled_only else seq.regions | ||
| ) | ||
| return [ | ||
| ElectronAnalyserRegionDetector[ | ||
| TAbstractAnalyserDriverIO, TAbstractBaseRegion | ||
|
|
@@ -201,7 +187,7 @@ def create_region_detector_list( | |
|
|
||
|
|
||
| GenericElectronAnalyserDetector = ElectronAnalyserDetector[ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do you need this class here? it seems to be used only in tests
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, this will be used in plan repo too.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. which plan repo? sm-bluesky?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm again in tests...:) |
||
| GenericSequence, GenericAnalyserDriverIO, GenericRegion | ||
| GenericAnalyserDriverIO, GenericRegion | ||
| ] | ||
| TElectronAnalyserDetector = TypeVar( | ||
| "TElectronAnalyserDetector", | ||
|
|
||
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import pytest | ||
|
|
||
| from dodal.devices.beamlines import b07, b07_shared, i09 | ||
| from dodal.devices.electron_analyser.base import GenericElectronAnalyserDetector | ||
| from dodal.devices.electron_analyser.specs import SpecsDetector | ||
| from dodal.devices.electron_analyser.vgscienta import VGScientaDetector | ||
|
|
||
|
|
||
| @pytest.fixture(params=["ew4000", "b07b_specs150"]) | ||
| def sim_detector( | ||
| request: pytest.FixtureRequest, | ||
| ew4000: VGScientaDetector[i09.LensMode, i09.PsuMode, i09.PassEnergy], | ||
| b07b_specs150: SpecsDetector[b07.LensMode, b07_shared.PsuMode], | ||
| ) -> GenericElectronAnalyserDetector: | ||
| detectors = [ew4000, b07b_specs150] | ||
| for detector in detectors: | ||
| if detector.name == request.param: | ||
| return detector | ||
|
|
||
| raise ValueError(f"Detector with name '{request.param}' not found") |
Uh oh!
There was an error while loading. Please reload this page.