Skip to content

Conversation

rtuck99
Copy link
Contributor

@rtuck99 rtuck99 commented Sep 16, 2025

Fixes

See mx-bluesky PR

This changes fast_grid_scan.set_fast_grid_scan_params() plan to delegate to the FastGridScanCommon.prepare() method.

prepare() combines setting the parameters with checking that they are valid, if the parameters are invalid, a TimeoutError will occur.

  • Possibly we could raise a more specific exception here; SampleException is currently in mx-bluesky, but we could define our own
  • Following discussion with @LeandroMartinsdS this now also checks x/y/z SCAN_VALID PVs
  • We now check that the readbacks are good before proceeding to check validity.

Instructions to reviewer on how to test:

  1. Tests pass
  2. Soak test of gridscans to see if issue recurs

Checks for reviewer

  • Would the PR title make sense to a scientist on a set of release notes
  • If a new device has been added does it follow the standards
  • If changing the API for a pre-existing device, ensure that any beamlines using this device have updated their Bluesky plans accordingly
  • Have the connection tests for the relevant beamline(s) been run via dodal connect ${BEAMLINE}

@rtuck99 rtuck99 force-pushed the mx-bluesky_1189_scan_invalid branch from 74d0a46 to 4fde8a1 Compare September 16, 2025 10:08
Copy link

codecov bot commented Sep 16, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.88%. Comparing base (c59932b) to head (9753042).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1540   +/-   ##
=======================================
  Coverage   98.88%   98.88%           
=======================================
  Files         260      260           
  Lines        9472     9493   +21     
=======================================
+ Hits         9366     9387   +21     
  Misses        106      106           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@rtuck99 rtuck99 force-pushed the mx-bluesky_1189_scan_invalid branch from 1ad901c to 8171d36 Compare September 25, 2025 13:29
@rtuck99 rtuck99 marked this pull request as ready for review September 25, 2025 14:33
@rtuck99 rtuck99 requested a review from a team as a code owner September 25, 2025 14:33
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.

This is so much cleaner. A few comments in code

Possibly we could raise a more specific exception here; SampleException is currently in mx-bluesky, but we could define our own

Yh, I think we should. I think it's a bit more readable, plus I don't think it's currently possible to get a TimeoutError from the prepare for any reason other than the check tasks

Comment on lines 224 to 227
self.x_scan_valid = epics_signal_r(float, f"{prefix}X_SCAN_VALID")
self.y_scan_valid = epics_signal_r(float, f"{prefix}Y_SCAN_VALID")
self.z_scan_valid = epics_signal_r(float, f"{prefix}Z_SCAN_VALID")
self.scan_invalid = epics_signal_r(float, f"{prefix}SCAN_INVALID")
Copy link
Contributor

Choose a reason for hiding this comment

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

Must: FastGridScanCommon is also used by i02_1, where these PVs don't exist. I.e. if you do a dodal connect i02_1 this fails

) -> MotionProgram: ...

@AsyncStatus.wrap
async def prepare(self, value: ParamType):
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks, this is a lot nicer than doing it plan side!


LOGGER.info("Applying gridscan parameters...")
# Create arguments for bps.mv
for key, signal in self.movable_params.items():
Copy link
Contributor

Choose a reason for hiding this comment

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

Could: Can we make movable_params private now?

# wait for parameter readbacks to update
await asyncio.gather(*set_statuses)

LOGGER.info("Readbacks confirmed, waiting for validity checks to pass...")
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 isn't reading the RBVs. The set logic on epics_signal_rw_rbv is to return when we get a put callback on the PV. See bluesky/ophyd-async#996 for some discussion on how this might change. Solution is to either:

Copy link
Contributor Author

Choose a reason for hiding this comment

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

A bit confused about this - these statuses are from set_and_wait_for_value() which does actually do an observe_value() on the signal. I appreciate these aren't motors and so don't have a separate RBV PV, but surely as they are rw signals it does actually read the value back from the device?

Comment on lines +316 to +325
# XXX Can we use x/y/z scan valid to distinguish between SampleException/pin invalid
# and other non-sample-related errors?
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'm not sure if there are cases where the scan is invalid but it's not a sample error but maybe I'm missing something?

Comment on lines 318 to 329
check_tasks = []
for signal, expected_value in {
self.x_scan_valid: 1,
self.y_scan_valid: 1,
self.z_scan_valid: 1,
self.scan_invalid: 0,
}.items():
check_tasks.append(
wait_for_value(
signal, expected_value, timeout=self.VALIDITY_CHECK_TIMEOUT
)
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit:

Suggested change
check_tasks = []
for signal, expected_value in {
self.x_scan_valid: 1,
self.y_scan_valid: 1,
self.z_scan_valid: 1,
self.scan_invalid: 0,
}.items():
check_tasks.append(
wait_for_value(
signal, expected_value, timeout=self.VALIDITY_CHECK_TIMEOUT
)
)
check_tasks = [
wait_for_value(signal, expected_value, timeout=self.VALIDITY_CHECK_TIMEOUT)
for signal, expected_value in {
self.x_scan_valid: 1,
self.y_scan_valid: 1,
self.z_scan_valid: 1,
self.scan_invalid: 0,
}.items()
]

Much of a muchness though

return epics_signal_rw(int, f"{prefix}Y_COUNTER")


def set_fast_grid_scan_params(scan: FastGridScanCommon[ParamType], params: ParamType):
Copy link
Contributor

Choose a reason for hiding this comment

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

Could: Maybe a docstring in here on what to expect if it's invalid

@rtuck99 rtuck99 force-pushed the mx-bluesky_1189_scan_invalid branch from fa5cc9f to b3c0ce0 Compare October 7, 2025 09:30
@rtuck99 rtuck99 requested a review from DominicOram October 7, 2025 13:44
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