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

(#475) Xray-centre and collect on multiple centres #553

Open
wants to merge 15 commits into
base: main
Choose a base branch
from

Conversation

rtuck99
Copy link
Contributor

@rtuck99 rtuck99 commented Oct 4, 2024

Implements #475

See also DiamondLightSource/dodal#814

This implements multiple rotations on multiple centres for the load_centre_collect_full_plan.
The behaviour of other plans should remain unchanged, with moving to a single centre.
By default load_centre_collect also only does a single centre.
To specify multiple centres, include the following in the request parameters:

  "select_centres": {
    "name": "top_n_by_max_count",
    "n": 5
  },

where n is however many centres to select

Copy link

codecov bot commented Oct 4, 2024

Codecov Report

Attention: Patch coverage is 96.63462% with 7 lines in your changes missing coverage. Please review.

Project coverage is 78.58%. Comparing base (0ff840f) to head (d3da321).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #553      +/-   ##
==========================================
+ Coverage   78.21%   78.58%   +0.37%     
==========================================
  Files          92       94       +2     
  Lines        6797     6943     +146     
==========================================
+ Hits         5316     5456     +140     
- Misses       1481     1487       +6     
Components Coverage Δ
i24 SSX 57.17% <ø> (ø)
hyperion 96.22% <96.63%> (-0.02%) ⬇️
other 100.00% <ø> (ø)

Copy link
Contributor

@DominicOram DominicOram left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! This is great, we will see how it goes on Monday. Some comments in code, think a few places where we should probably all talk it through together.

Additionally, for multipin tests we're also probably going to need something that gives us the top result in each segment e.g. for a 100 box long multipin with 5 samples in we would want the top result in 0-20, 20-40 etc. We can do this on the beamline for the tests next week and then maybe pull it into a better defined issue.

pass


def change_aperture_then_centre(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should: I think centre here is misleading as upon first reading it I thought it meant you were about to do a pin tip/xrc. Maybe change_aperture_and_move_to_crystal?

from mx_bluesky.hyperion.tracing import TRACER


class CentringComposite(Protocol):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could: Feels like a composite might be overkill here, we could just have change_aperture_then_centre take a ApertureScatterguard and a Smargon



@dataclasses.dataclass
class FlyscanResult:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should: It's more a XRCResult than flyscan result. We could do a XRC as a step scan and produce these results.

@@ -112,26 +116,27 @@ def sample_motors(self) -> Smargon:
return self.smargon


class FlyscanEventHandler:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should: For other events we use CallbackBase. I can't see why you can't here and would be good to keep consistency.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's overkill for what should just be a simple event handler. What does it give us?

Comment on lines 120 to 121
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should: It looks weird to me to take args/kwargs when they're never used

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's a leftover from when I first started off inheriting from DocumentRouter and decided it was too much faff

@@ -242,6 +262,38 @@ def run_gridscan_and_move(
yield from bps.wait()


def _xrc_result_to_flyscan_result(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should: I think it is cleaner, and more idiomatic of bluesky, to move this calculation to the FlyscanEventHandler. It should be able to get everything it needs for the calculation by the events produced throughout the plan. This would reduce the complexity of the plans themselves and change _fire_flyscan_result_event to just be a bps.read(zocalo) Probably needs a discussion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started doing this and have run into complications with unit tests as now ThreeDGridscan needs to be injected in lots of places. Also I think I have run into additional complications due to #220 which previously wasn't an issue because the tests either didn't need to account for this bug or did it both ways which cancelled each other out.

Comment on lines 69 to 71
selection_params = params.select_centres
selection_func = getattr(flyscan_result, selection_params.name) # type: ignore
assert callable(selection_func)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should: I don't think letting the user provide a function name like this is very good. It's quite brittle to name changes/argument changes and I don't think we need this much flexibility right now anyway.

Comment on lines 78 to 83
for hit in hits:
LOGGER.info(f"Performing rotations for {hit}")
yield from change_aperture_then_centre(hit, composite)
yield from multi_rotation_scan(
composite, params.multi_rotation_scan, oav_params
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must: I think what we actually want to do is take all the hits and wrap them up in one call to multi_rotation_scan with different x/y/z starts. Otherwise we're going to get the detector re-arming between them all etc. For a first pass this probably means just stay at the same aperture for each of them, which is fine.

@@ -105,15 +111,27 @@ def pin_tip_centre_then_xray_centre(
oav_config_file: str = OAV_CONFIG_JSON,
) -> MsgGenerator:
"""Starts preparing for collection then performs the pin tip centre and xray centre"""
# TODO listen for flyscan results and then centre
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should: We're doing this, no need for the comment

pin_centre_then_xray_centre_plan(composite, parameters, oav_config_file),
group=CONST.WAIT.GRID_READY_FOR_DC,
)
flyscan_event_handler = FlyscanEventHandler()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should: This pattern is used quite a bit now, I think it's probably worth making a wrapper of something like:

def do_plan_and_move_to_xrc_result(plan):
    """Do the specified plan then move to whatever result XRC gives back"""
    yield from bpp.subs_wrapper(plan, flyscan_event_handler := FlyscanEventHandler())
    flyscan_results = flyscan_event_handler.flyscan_results
    assert (
        flyscan_results
    ), "Flyscan result event not received or no crystal found and exception not raised"
    yield from change_aperture_then_centre(flyscan_results[0], composite)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't partly as we are ultimately removing most of the places where it's used anyway

Base automatically changed from 470_full_plan_to_replace_execute_request to main October 7, 2024 10:11
@rtuck99 rtuck99 marked this pull request as ready for review October 15, 2024 16:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants