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

Finish setting up an ophyd_async OAV #857

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

Conversation

noemifrisina
Copy link
Collaborator

@noemifrisina noemifrisina commented Oct 21, 2024

Closes #716
Closes #824

  • Create an ophyd_async MJPG area detector plugin to replace old one
  • Re-write snapshot devices to inherit from new MJPG
  • Add snapshots to ophyd_async OAV
  • Use async OAV in beamline device instantiation
  • Add a small CAM plugin with minimum requirements for hyperion
  • Add unit tests, fix system tests to work with async device
  • Remove all obsolete code and tests

Instructions to reviewer on how to test:

  1. Check that all the functionality of the old ophyd OAV device and MJPG plugin is covered by the new ophyd_async code
  2. Check connection for all mx beamlines still works
  3. Run tests and confirm they pass
  4. Confirm tests in mx-bluesky still pass (see mx-bluesky#594)

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}

Copy link

codecov bot commented Oct 21, 2024

Codecov Report

Attention: Patch coverage is 98.55769% with 3 lines in your changes missing coverage. Please review.

Project coverage is 95.53%. Comparing base (c89282a) to head (f30a519).

Files with missing lines Patch % Lines
src/dodal/devices/oav/oav_detector.py 94.82% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #857      +/-   ##
==========================================
- Coverage   95.59%   95.53%   -0.06%     
==========================================
  Files         125      127       +2     
  Lines        5422     5378      -44     
==========================================
- Hits         5183     5138      -45     
- Misses        239      240       +1     

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

@noemifrisina
Copy link
Collaborator Author

I realised once I started updating the hyperion side that we do set some of the cam plugin. For now, I just made a small device here with the minimum requirements, but I'm wondering iff it's worth opening an issue to do it properly in the future?

Also, another pair of eyes on the codecov patch would help, please. I think I covered all the old tests and I can't figure out what's missing that makes the coverage decrease...

@noemifrisina noemifrisina marked this pull request as ready for review October 24, 2024 11:59
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.

Great, thanks. Almost there but I added a few comments

Comment on lines +24 to +30
self.color_mode = epics_signal_rw(ColorMode, "GC_BalRatioSelector")
self.acquire_period = epics_signal_rw(float, "AcquirePeriod")
self.acquire_time = epics_signal_rw(float, "AcquireTime")
self.gain = epics_signal_rw(float, "Gain")

self.array_size_x = epics_signal_r(int, "ArraySizeX_RBV")
self.array_size_y = epics_signal_r(int, "ArraySizeY_RBV")
Copy link
Contributor

Choose a reason for hiding this comment

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

Must: these aren't connecting in dodal connect i03 as they need the PV prefix

Comment on lines +29 to +30
self.x_size = epics_signal_r(int, prefix + "ArraySize1_RBV")
self.y_size = epics_signal_r(int, prefix + "ArraySize2_RBV")
Copy link
Contributor

Choose a reason for hiding this comment

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

Must: these aren't connecting in dodal connect i03 as you're missing a colon

Comment on lines +32 to +34
# TODO check type of these two
self.input_rbpv = epics_signal_r(str, prefix + "NDArrayPort_RBV")
self.input_plugin = epics_signal_rw(str, prefix + "NDArrayPort")
Copy link
Contributor

Choose a reason for hiding this comment

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

Should: These two PVs aren't used anyway, lets just remove them

await self.last_saved_path.set(path, wait=True)

@AsyncStatus.wrap
async def trigger(self):
"""This takes a snapshot image from the MJPG stream and send it to the
post_processing method, expected to be implemented by a child of this class.

It is the responsibility of the child class to save any resulting images.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: by calling _save_image

Comment on lines +72 to +78
if not response.ok:
LOGGER.error(
f"OAV responded with {response.status}: {response.reason}."
)
raise ClientConnectionError(
f"OAV responded with {response.status}: {response.reason}."
)
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 we can just do response.raise_for_status() or actually ClientSession(raise_for_status=True)

) -> np.ndarray:
beam_distance_px: Pixel = oav_params.calculate_beam_distance(*pixel)
beam_distance_px: Pixel = calculate_beam_distance((beam_centre), *pixel)
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: These brackets seem unrequired

oav_config = OAVConfig(ZOOM_LEVELS_XML, DISPLAY_CONFIGURATION)
async with DeviceCollector():
oav = OAV("", config=oav_config, name="oav")
await oav.connect()
Copy link
Contributor

Choose a reason for hiding this comment

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

Should: DeviceCollector already does the connect for you

autospec=True,
)
@patch("dodal.devices.areadetector.plugins.MJPG.Image")
async def test_snapshot_trigger_fails_in_post_processing_withouth_raising_error(
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Typo on without

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 also think we probably do want it to raise

Comment on lines +94 to +99
# Set new directory and test that it's created
set_mock_value(snapshot.directory, "new_dir")

await snapshot.trigger()

mock_mkdir.assert_called_once()
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: I would test this in a separate test that's just testing a new folder is created i.e. like test_given_directory_not_existing_when_snapshot_triggered_then_directory_created

Comment on lines +84 to +92
mock_get.return_value.__aenter__.return_value = (mock_response := AsyncMock())
mock_response.ok = True
mock_response.read.return_value = (test_data := b"TEST")

mock_aio_open = mock_aiofiles.open
mock_aio_open.return_value.__aenter__.return_value = (mock_file := AsyncMock())

mock_open = patch_image.open
mock_open.return_value.__aenter__.return_value = test_data
Copy link
Contributor

Choose a reason for hiding this comment

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

Should: You do this mocking a few times, I think pull it into a helper function

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.

Make an ophyd-async MJPG plugin for the oav Convert the OAV to ophyd-async
2 participants