-
Notifications
You must be signed in to change notification settings - Fork 5
Conversation
Unsure if it's a multi-step process, but I think the eventual aim should be to remove the experiment registry entirely and just replace it with a hierarchy of plans. I.e. there is a top level plan called The philosophy here is that blueapi can be a nice, stable, standardised core that's the same for everyone, and per-beamline customization is kept in the plans as far as is reasonable. This is a very core-ivory-tower point of view though and hasn't yet been tested in anger, so I welcome differing opinions @DominicOram and @Tom-Willemsen. We deliberately left this part of the design loose in anticipation of feedback. |
I agree with what you've written, and I'm hoping that this PR doesn't conflict too much with that view. The only additional coupling to from blueapi import inject_composite
@dataclasses.dataclass
class MyPlanComposite:
backlight: Backlight
eiger: Eiger
...
def my_experiment_plan(
composite: MyPlanComposite = inject_composite(MyPlanComposite),
...
):
yield from prepare(composite)
yield from do_it(composite)
yield from clean_up(composite) where The main thing I was trying to avoid was having to write something very drawn out like: from blueapi import inject
def my_experiment_plan(
backlight: Backlight = inject("backlight"),
eiger: Eiger = inject("eiger"),
...<20 more devices>...
):
yield from prepare(eiger, backlight, <20 more devices>)
yield from do_it(eiger, backlight, <20 more devices>)
yield from clean_up(eiger, backlight, <20 more devices>) in every single plan (and passing through lots of devices into subplans too). I think the option to inject single device(s) should remain though, for simpler plans that only need a limited number of devices. This PR is indeed just a first step though - moving away from hard-coded Does that sound sensible? |
Yes, this was my understanding of the end goal. This is a step towards that to try and work incrementally to where we want to be. I think the next issue is probably DiamondLightSource/mx-bluesky#339 then I think a full removal of |
@DominicOram and @Tom-Willemsen, that all sounds good to me! Will let you know if I have any other 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.
Great, thank you. All looks a lot tidier
src/hyperion/experiment_plans/tests/test_grid_detect_then_xray_centre_plan.py
Outdated
Show resolved
Hide resolved
src/hyperion/experiment_plans/tests/test_grid_detect_then_xray_centre_plan.py
Outdated
Show resolved
Hide resolved
Codecov Report
@@ Coverage Diff @@
## main DiamondLightSource/hyperion#871 +/- ##
==========================================
+ Coverage 93.03% 93.34% +0.31%
==========================================
Files 51 52 +1
Lines 2456 2526 +70
==========================================
+ Hits 2285 2358 +73
+ Misses 171 168 -3
📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
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 we can also now remove both get_beamline_prefixes
and associated tests as we're doing this in dodal
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 in code but mostly there
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.
Great, thank you Tom
Fixes #867
This refactors our hyperion plans to no longer refer to things like
i03.backlight()
directly, and instead to pull devices out of ablueapi
context.The main approach at present is that each class defines a composite of devices it needs (as a dataclass), in it's setup method.
as an example, something like:
In the plan's
create_devices
, this composite is then instantiated with the appropriate devices from theblueapi
context. This composite instance is then passed as one of the arguments to the plan, and relevant devices (or the entire composite) passed down into sub-plans as necessary.I've tried to design this so that it should be relatively easy to move to blueapi's
inject
mechanism when we do DiamondLightSource/mx-bluesky#339 (might need a thin shim), as now all of the dependencies of each plan are passed around as explicit arguments rather than implicit and scattered throughout sub-plans.I've tried to keep the API type-safe for developers where possible, as before, which is why I chose to use a dataclasses in the above format rather than passing around e.g. a
Dict[str, Device]
. This also lets us check we got a device of the expected type out of the context.Some API decisions which I'm not necessarily sure about:
wait_for_connection=False
is a bit hacky, it's currently "known about" in two places, one when you setup the context (which honors the wait_for_connection setting) and one when the device composite is actually created (at which point you're starting a plan and therefore always need the devices to be connected).blueapi
will have to be responsible for making sure that any devices it injects are actually connected at the point they're useddevice_instantiation
(for example - loading aperture positions). At the point when we're building thecontext
we don't know which plan we'll be running but still need to set up the devices. Currently I've moved loading aperture positions into a__post_init__
on the dataclasses described above, so that this logic happens when the relevant device is about to be used.blueapi
will then somehow have to be told about any post-device-creation initialisation that needs to be done.To test
i03.<anything>
any more.mock_backlight = i03.backlight(fake_with_ophyd_sim=True)
. This seems ok to me as it's just for simulated devices.main
and still fail on this branch (e.g. rotation scans, fgs).