-
Notifications
You must be signed in to change notification settings - Fork 8
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
Ophyd async slits #431
Ophyd async slits #431
Conversation
5acee35
to
83a63db
Compare
src/dodal/devices/s4_slit_gaps.py
Outdated
Constructor, formats prefix with indices for sub-devices. For example: | ||
S4SlitGapsGroup("MY-SLITS-{0:02d}:", range(5)) will populate the group with 4 | ||
S4SlitGaps devices with prefixes MY-SLITS-00, MY-SLITS-01, MY-SLITS-02, | ||
MY-SLITS-03. The index to access them will be the same as the PV number, so | ||
MY-SLITS-02 is accessed via group.slits[2]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@DiamondJoseph and @DominicOram I'm not sure about this, just an idea I had to save boilerplate. See the i22 and p38 modules for example usage. Interested in your thoughts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think at the very least, indices should be a Sequence[int], in case Slits[n] are disabled temporarily.
Looks like this fits with the ophyd_async ADR https://github.com/bluesky/ophyd-async/blob/7be73e3ce0f79fca2e02f77f366792ee84586ed7/docs/developer/explanations/decisions/0006-procedural-device-definitions.rst#L58 for proceedurally created devices.
I do wish it was just slits[1] rather than group.slits[1]: does group.name = "" work with blueapi still being able to get group.slits[1]?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with Sequence[int]
, for why the group adds another layer to the tree, see this comment bluesky/ophyd-async#181 (comment)
That said, I do agree it would be nicer, I wonder if there's a way of subclassing DeviceVector
to incorporate the PV prefixing logic...
Tagging @coretl in case he has ideas
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a big fan of this. I think from a use perspective doing i03.slits_1()
is more obvious than i03.slits().slits[1]
given that this is how all other devices work. In other devices we only group like this if the devices make sense for the user to move together, does it make sense to the user for all of the slits to be one composite? What is one of the slit 2 fails to connect but we only need slit 4 in the plan? @dperl-dls, what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I'm not a fan of a composite device here, I'd prefer slits1
, slits2
, etc.
However, if you decide you really want it, it does occur to me that multiple inheritance of DeviceVector
and StandardDetector
(rather than your existing nesting of DeviceVector
within StandardDetector
might work to squash down the layers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, I think we just remove the group entirely if it doesn't make semantic sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense and I agree with the user perspective. @DominicOram how about i03.slits()[1]?
Better but I still think separate is the best for the user, as @Tom-Willemsen says. If we're only doing this to avoid boilerplate then all for thinking about ways to make the beamline
files less boilerplate-y without changing the interface
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although this does create a lot of additional boilerplate in i22.py
so should think more about it long-term
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not opposed to the boilerplate in this case. To be honest, long term we're probably going to need to split i22
into modules like i22.slits
, i22.sample_environment
, and so on, and the top-level i22
will just import *
from each of those.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I fear the boilerplate just because of how much GDA's per-beamline config has ballooned over the years, it's ended up split into files and subdirectories etc. in a very similar way to your suggestion here. I suppose that's not the end of the world but it would be nice to have a more concise description of the beamline to work with.
src/dodal/devices/s4_slit_gaps.py
Outdated
self.x_gap = Motor(prefix + "X:SIZE") | ||
self.y_gap = Motor(prefix + "Y:SIZE") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@DominicOram Renamed from xgap
and ygap
on the original for more standard pythonicness, but can revert if it will cause pain for hyperion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will cause problems but we can deal with it. Can you wait for a linked Hyperion PR before merging this though?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, no problem
@dan-fernandes how does this interact with the code in #315? Does this supersede some of it? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments. Annoyingly we're more stuck than I thought we were on on getting the PV names changed for i03 too. Working on it...
src/dodal/devices/s4_slit_gaps.py
Outdated
|
||
|
||
class S4SlitGaps(Device): | ||
"""Note that the S4 slits have a different PV fromat to other beamline slits""" | ||
class S4SlitGaps(StandardReadable): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should: Why are these named after S4? My understanding is that this in now a generic slit class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because I don't know what S4 is :)
Will rename to Slits
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incidentally, and at risk of betraying my woeful knowledge of xray optics, if either you or @Tom-Willemsen can come up with a better docstring than mine then I'm all ears. Mine is basically "erm, it's a set of some sort of slits...?"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a 4-blade slit set defined by a gap and a centre for each pair of blades.
The things I can immediately think of which we want to diambiguate from are:
- Having different numbers of blades, e.g. a 2 blade vertical slit set might exist on some beamlines, this would only define the beam in a vertical oritentation.
- Definining the slit set by absolute positions of each blade rather than gap and centre. Not sure, but I'd wager at least some beamlines do this - e.g. for scanning in each blade against the beam individually
Because I don't know what S4
Logically the fourth slit set along the x-ray beam path... However the numbering can be illogical sometimes. As an example VMXi used to have a slit set S2, but this was removed some time ago, so now their slits along the beam path are S1
, S3
, ...
Feel free to swing by my desk if you need...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, so could actually call the class Slits4Blade
or something similar? For absolute vs. relative it sounds like those things can coexist in the same device?
I'd love to swing by but I'm sick!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can probably assume 4-blade is the standard case, so I think naming the class Slits
is fine as long as the docstring clarifies it's a 4-blade set.
For absolute vs. relative it sounds like those things can coexist in the same device?
Yes, care is just needed because you then have multiple PVs which affect the same physical blade. (e.g. moving the north blade will change the vertical gap and vice versa).
Does a picture like this help to visualise what's going on?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, quite a lot, thanks!
src/dodal/devices/s4_slit_gaps.py
Outdated
super().__init__(name) | ||
|
||
|
||
class S4SlitGapsGroup(StandardReadable): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should: As above, not sure why these have S4 in the name?
src/dodal/devices/s4_slit_gaps.py
Outdated
self.x_gap = Motor(prefix + "X:SIZE") | ||
self.y_gap = Motor(prefix + "Y:SIZE") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will cause problems but we can deal with it. Can you wait for a linked Hyperion PR before merging this though?
src/dodal/devices/s4_slit_gaps.py
Outdated
Constructor, formats prefix with indices for sub-devices. For example: | ||
S4SlitGapsGroup("MY-SLITS-{0:02d}:", range(5)) will populate the group with 4 | ||
S4SlitGaps devices with prefixes MY-SLITS-00, MY-SLITS-01, MY-SLITS-02, | ||
MY-SLITS-03. The index to access them will be the same as the PV number, so | ||
MY-SLITS-02 is accessed via group.slits[2]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a big fan of this. I think from a use perspective doing i03.slits_1()
is more obvious than i03.slits().slits[1]
given that this is how all other devices work. In other devices we only group like this if the devices make sense for the user to move together, does it make sense to the user for all of the slits to be one composite? What is one of the slit 2 fails to connect but we only need slit 4 in the plan? @dperl-dls, what do you think?
src/dodal/beamlines/i22.py
Outdated
return device_instantiation( | ||
Slits, | ||
"slits-01", | ||
"-AL-SLITS-01:", | ||
wait_for_connection, | ||
fake_with_ophyd_sim, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could: I would still want the slits_x()
interface but no reason you can't hide it:
def _generic_slit(slit_num, wait_for_connection, fake):
return device_instantiation(
Slits,
f"slits-0{slit_num}",
f"-AL-SLITS-0{slit_num}:",
wait_for_connection,
fake_with_ophyd_sim,
)
def slits_1(...):
return _generic_slit(1, ...)
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, is there currently anywhere sensible to put _generic_slit
so that it can be shared between the i22
and p38
modules?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm.. I guess devices.util.something
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up putting it in a private module in beamlines
because otherwise we were importing device_instantiation
from beamline.beamline_utils
into devices.util.something
, then importing that back into beamlines.i22
, which I could lead to circular import troubles at some point. But let me know what you think, happy to change it
I agree with this - I think we rarely if ever need to coordinate movements between different slits, except, like, setting the whole beamline to some standard state. It's a little academic because slits 1&2 should never actually be offline if we're running stuff, but there's no reason to actively make devices connect to them when we only need |
800369c
to
9caec0d
Compare
9caec0d
to
d75a999
Compare
Port S4SlitGaps to ophyd-async. Add tests to prove it reads correctly. Also create a group object for bunches of slits.
8fe6867
to
a01e63b
Compare
As discussed with @DominicOram, @dperl-dls and @olliesilvester, the work to standardise the slits PVs has encountered complications so we are going to keep both versions of the slits device for now. Once that work is done we can action #462 and rationalise the implementations. |
from .beamline_utils import device_instantiation | ||
|
||
|
||
@skip_device() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this decorator do anything here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me, don't think it will have any affect on MX yet but looks like we will be able to switch to it easily when we get round to #462
Fixes #384
Port S4SlitGaps to ophyd-async. Add tests to prove it reads correctly. Also create a group object for bunches of slits. Add slits config for I22 and P38.
Instructions to reviewer on how to test:
Checks for reviewer