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

Configure shutter to always use the manual/auto option #446

Merged
merged 6 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ dependencies = [
"ophyd == 1.9.0",
"ophyd-async >= 0.3a5",
"bluesky >= 1.13.0a4",
"dls-dodal @ git+https://github.com/DiamondLightSource/dodal.git",
"dls-dodal @ git+https://github.com/DiamondLightSource/dodal.git@e62835c227fb0010560762c190a60322079aaf88",
]


Expand Down
43 changes: 23 additions & 20 deletions src/mx_bluesky/hyperion/device_setup_plans/setup_zebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@
import bluesky.preprocessors as bpp
from blueapi.core import MsgGenerator
from dodal.devices.zebra import (
AUTO_SHUTTER_GATE,
AUTO_SHUTTER_INPUT,
DISCONNECT,
IN1_TTL,
IN3_TTL,
IN4_TTL,
OR1,
PC_GATE,
PC_PULSE,
TTL_DETECTOR,
TTL_PANDA,
TTL_SHUTTER,
TTL_XSPRESS3,
ArmDemand,
EncEnum,
I03Axes,
RotationDirection,
SoftInState,
Zebra,
)

Expand Down Expand Up @@ -61,6 +61,18 @@ def disarm_zebra(zebra: Zebra):
yield from bps.abs_set(zebra.pc.arm, ArmDemand.DISARM, wait=True)


def set_shutter_auto_input(
zebra: Zebra, input: int, group="set_shutter_trigger", wait=True
):
"""Set the input that the shutter uses when set to auto.

For more details see the ZebraShutter device."""
auto_shutter_control = zebra.logic_gates.and_gates[AUTO_SHUTTER_GATE]
yield from bps.abs_set(
auto_shutter_control.sources[AUTO_SHUTTER_INPUT], input, group, wait
)


@bluesky_retry
def setup_zebra_for_rotation(
zebra: Zebra,
Expand Down Expand Up @@ -100,8 +112,6 @@ def setup_zebra_for_rotation(
)
yield from bps.abs_set(zebra.pc.dir, direction.value, group=group)
LOGGER.info("ZEBRA SETUP: START")
# must be on for shutter trigger to be enabled
yield from bps.abs_set(zebra.inputs.soft_in_1, SoftInState.YES, group=group)
# Set gate start, adjust for shutter opening time if necessary
LOGGER.info(f"ZEBRA SETUP: degrees to adjust for shutter = {shutter_opening_deg}")
LOGGER.info(f"ZEBRA SETUP: start angle start: {start_angle}")
Expand All @@ -117,8 +127,8 @@ def setup_zebra_for_rotation(
yield from bps.abs_set(zebra.pc.pulse_start, abs(shutter_opening_s), group=group)
# Set gate position to be angle of interest
yield from bps.abs_set(zebra.pc.gate_trigger, axis.value, group=group)
# Trigger the shutter with the gate (from PC_GATE & SOFTIN1 -> OR1)
yield from bps.abs_set(zebra.output.out_pvs[TTL_SHUTTER], OR1, group=group)
# Trigger the shutter with the gate
yield from set_shutter_auto_input(zebra, PC_GATE)
# Trigger the detector with a pulse
yield from bps.abs_set(zebra.output.out_pvs[TTL_DETECTOR], PC_PULSE, group=group)
# Don't use the fluorescence detector
Expand All @@ -132,7 +142,7 @@ def setup_zebra_for_rotation(
@bluesky_retry
def setup_zebra_for_gridscan(zebra: Zebra, group="setup_zebra_for_gridscan", wait=True):
yield from bps.abs_set(zebra.output.out_pvs[TTL_DETECTOR], IN3_TTL, group=group)
yield from bps.abs_set(zebra.output.out_pvs[TTL_SHUTTER], IN4_TTL, group=group)
yield from set_shutter_auto_input(zebra, IN4_TTL)
yield from bps.abs_set(zebra.output.out_pvs[TTL_XSPRESS3], DISCONNECT, group=group)
yield from bps.abs_set(zebra.output.pulse_1.input, DISCONNECT, group=group)

Expand All @@ -141,23 +151,16 @@ def setup_zebra_for_gridscan(zebra: Zebra, group="setup_zebra_for_gridscan", wai


@bluesky_retry
def set_zebra_shutter_to_manual(
zebra: Zebra, group="set_zebra_shutter_to_manual", wait=True
def tidy_up_zebra_after_gridscan(
zebra: Zebra, group="tidy_up_zebra_after_gridscan", wait=True
) -> MsgGenerator:
yield from bps.abs_set(zebra.output.out_pvs[TTL_DETECTOR], PC_PULSE, group=group)
yield from bps.abs_set(zebra.output.out_pvs[TTL_SHUTTER], OR1, group=group)
yield from set_shutter_auto_input(zebra, PC_GATE)

if wait:
yield from bps.wait(group, timeout=ZEBRA_STATUS_TIMEOUT)


@bluesky_retry
def make_trigger_safe(zebra: Zebra, group="make_zebra_safe", wait=True):
yield from bps.abs_set(
zebra.inputs.soft_in_1, SoftInState.NO, wait=wait, group=group
)


@bluesky_retry
def setup_zebra_for_panda_flyscan(
zebra: Zebra, group="setup_zebra_for_panda_flyscan", wait=True
Expand All @@ -166,9 +169,9 @@ def setup_zebra_for_panda_flyscan(
yield from bps.abs_set(zebra.output.out_pvs[TTL_DETECTOR], IN1_TTL, group=group)

# Forwards signal from PPMAC to fast shutter. High while panda PLC is running
yield from bps.abs_set(zebra.output.out_pvs[TTL_SHUTTER], IN4_TTL, group=group)
yield from set_shutter_auto_input(zebra, IN4_TTL)

yield from bps.abs_set(zebra.output.out_pvs[3], DISCONNECT, group=group)
yield from bps.abs_set(zebra.output.out_pvs[TTL_XSPRESS3], DISCONNECT, group=group)

yield from bps.abs_set(
zebra.output.out_pvs[TTL_PANDA], IN3_TTL, group=group
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from dodal.devices.undulator import Undulator
from dodal.devices.xbpm_feedback import XBPMFeedback
from dodal.devices.zebra import Zebra
from dodal.devices.zebra_controlled_shutter import ZebraShutter, ZebraShutterControl
from dodal.devices.zocalo.zocalo_results import (
ZOCALO_READING_PLAN_NAME,
ZOCALO_STAGE_GROUP,
Expand All @@ -57,9 +58,9 @@
setup_panda_for_flyscan,
)
from mx_bluesky.hyperion.device_setup_plans.setup_zebra import (
set_zebra_shutter_to_manual,
setup_zebra_for_gridscan,
setup_zebra_for_panda_flyscan,
tidy_up_zebra_after_gridscan,
)
from mx_bluesky.hyperion.device_setup_plans.xbpm_feedback import (
transmission_and_xbpm_feedback_for_collection_decorator,
Expand Down Expand Up @@ -97,6 +98,7 @@ class FlyScanXRayCentreComposite:
panda: HDFPanda
panda_fast_grid_scan: PandAFastGridScan
robot: BartRobot
sample_shutter: ZebraShutter

@property
def sample_motors(self) -> Smargon:
Expand Down Expand Up @@ -273,6 +275,13 @@ def run_gridscan(
LOGGER.info("Waiting for gridscan validity check")
yield from wait_for_gridscan_valid(feature_controlled.fgs_motors)

LOGGER.info("Set shutter to auto")
yield from bps.abs_set(
Copy link
Contributor

Choose a reason for hiding this comment

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

Could: Set shutter to auto (or check that it's in auto mode) during the individual setup_zebra plans. It's potentially misleading for plans like setup_zebra_for_gridscan to call set_shutter_auto_input while it's actually still in manual. Another option is for set_shutter_auto_input to include this check

fgs_composite.sample_shutter.control,
ZebraShutterControl.AUTO,
group=CONST.WAIT.GRID_READY_FOR_DC,
)

LOGGER.info("Waiting for arming to finish")
yield from bps.wait(CONST.WAIT.GRID_READY_FOR_DC)
yield from bps.stage(fgs_composite.eiger)
Expand Down Expand Up @@ -438,8 +447,11 @@ def _get_feature_controlled(
def _generic_tidy(
fgs_composite: FlyScanXRayCentreComposite, group, wait=True
) -> MsgGenerator:
LOGGER.info("Tidying up Zebra")
yield from set_zebra_shutter_to_manual(fgs_composite.zebra, group=group, wait=wait)
LOGGER.info("Tidying up Zebra and shutter")
yield from tidy_up_zebra_after_gridscan(fgs_composite.zebra, group=group, wait=wait)
Copy link
Contributor

Choose a reason for hiding this comment

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

Similar to my last comment, I think the tidy up plan itself should include setting the shutter to manual, otherwise the tidy_up_zebra_after_gridscan plan is a bit misleading

yield from bps.abs_set(
fgs_composite.sample_shutter.control, ZebraShutterControl.MANUAL
)
LOGGER.info("Tidying up Zocalo")
# make sure we don't consume any other results
yield from bps.unstage(fgs_composite.zocalo, group=group, wait=wait)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from dodal.devices.undulator import Undulator
from dodal.devices.xbpm_feedback import XBPMFeedback
from dodal.devices.zebra import Zebra
from dodal.devices.zebra_controlled_shutter import ZebraShutter
from dodal.devices.zocalo import ZocaloResults
from ophyd_async.panda import HDFPanda

Expand Down Expand Up @@ -83,6 +84,7 @@ class GridDetectThenXRayCentreComposite:
panda: HDFPanda
panda_fast_grid_scan: PandAFastGridScan
robot: BartRobot
sample_shutter: ZebraShutter


def create_devices(context: BlueskyContext) -> GridDetectThenXRayCentreComposite:
Expand Down Expand Up @@ -163,6 +165,7 @@ def run_grid_detection_plan(
zebra_fast_grid_scan=composite.zebra_fast_grid_scan,
dcm=composite.dcm,
robot=composite.robot,
sample_shutter=composite.sample_shutter,
),
create_parameters_for_flyscan_xray_centre(
parameters, grid_params_callback.get_grid_parameters()
Expand Down
13 changes: 11 additions & 2 deletions src/mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from dodal.devices.synchrotron import Synchrotron
from dodal.devices.undulator import Undulator
from dodal.devices.zebra import RotationDirection, Zebra
from dodal.devices.zebra_controlled_shutter import ZebraShutter, ZebraShutterControl
from dodal.plans.check_topup import check_topup_and_wait_if_necessary

from mx_bluesky.hyperion.device_setup_plans.manipulate_sample import (
Expand All @@ -37,7 +38,6 @@
from mx_bluesky.hyperion.device_setup_plans.setup_zebra import (
arm_zebra,
disarm_zebra,
make_trigger_safe,
setup_zebra_for_rotation,
)
from mx_bluesky.hyperion.experiment_plans.oav_snapshot_plan import (
Expand Down Expand Up @@ -70,6 +70,7 @@ class RotationScanComposite(OavSnapshotComposite):
undulator: Undulator
synchrotron: Synchrotron
s4_slit_gaps: S4SlitGaps
sample_shutter: ZebraShutter
zebra: Zebra
oav: OAV

Expand Down Expand Up @@ -215,6 +216,10 @@ def _rotation_scan_plan(
wait=True,
)

yield from bps.abs_set(
composite.sample_shutter.control, ZebraShutterControl.AUTO
)

yield from setup_zebra_for_rotation(
composite.zebra,
start_angle=motion_values.start_scan_deg,
Expand Down Expand Up @@ -283,7 +288,11 @@ def _cleanup_plan(composite: RotationScanComposite, **kwargs):
max_vel = yield from bps.rd(composite.smargon.omega.max_velocity)
yield from cleanup_sample_environment(composite.detector_motion, group="cleanup")
yield from bps.abs_set(composite.smargon.omega.velocity, max_vel, group="cleanup")
yield from make_trigger_safe(composite.zebra, group="cleanup")
yield from bps.abs_set(
composite.sample_shutter.control,
ZebraShutterControl.MANUAL,
group="cleanup",
)
yield from bpp.finalize_wrapper(disarm_zebra(composite.zebra), bps.wait("cleanup"))


Expand Down
1 change: 1 addition & 0 deletions src/mx_bluesky/hyperion/utils/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ def fake_create_rotation_devices():
zebra=zebra,
robot=robot,
oav=oav,
sample_shutter=i03.sample_shutter(fake_with_ophyd_sim=True),
)


Expand Down
9 changes: 9 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
from dodal.devices.util.test_utils import patch_motor as oa_patch_motor
from dodal.devices.webcam import Webcam
from dodal.devices.zebra import Zebra
from dodal.devices.zebra_controlled_shutter import ZebraShutter
from dodal.log import LOGGER as dodal_logger
from dodal.log import set_up_all_logging_handlers
from ophyd.sim import NullStatus
Expand Down Expand Up @@ -456,6 +457,11 @@ def thawer(RE) -> Generator[Thawer, Any, Any]:
yield i03.thawer(fake_with_ophyd_sim=True)


@pytest.fixture
def sample_shutter(RE) -> Generator[ZebraShutter, Any, Any]:
yield i03.sample_shutter(fake_with_ophyd_sim=True)


@pytest.fixture
def aperture_scatterguard(RE):
positions = {
Expand Down Expand Up @@ -565,6 +571,7 @@ def fake_create_rotation_devices(
dcm: DCM,
robot: BartRobot,
oav: OAV,
sample_shutter: ZebraShutter,
):
set_mock_value(smargon.omega.max_velocity, 131)
oav.zoom_controller.onst.sim_put("1.0x") # type: ignore
Expand All @@ -585,6 +592,7 @@ def fake_create_rotation_devices(
zebra=zebra,
robot=robot,
oav=oav,
sample_shutter=sample_shutter,
)


Expand Down Expand Up @@ -699,6 +707,7 @@ async def fake_fgs_composite(
panda=panda,
panda_fast_grid_scan=i03.panda_fast_grid_scan(fake_with_ophyd_sim=True),
robot=i03.robot(fake_with_ophyd_sim=True),
sample_shutter=i03.sample_shutter(fake_with_ophyd_sim=True),
)

fake_composite.eiger.stage = MagicMock(return_value=done_status)
Expand Down
5 changes: 3 additions & 2 deletions tests/system_tests/hyperion/experiment_plans/test_fgs_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ async def fxc_composite():
xbpm_feedback=i03.xbpm_feedback(fake_with_ophyd_sim=True),
zebra=i03.zebra(),
zocalo=zocalo,
sample_shutter=i03.sample_shutter(fake_with_ophyd_sim=True),
)

await composite.robot.barcode._backend.put("ABCDEFGHIJ") # type: ignore
Expand Down Expand Up @@ -179,7 +180,7 @@ def decorated_plan():
autospec=True,
)
@patch(
"mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan.set_zebra_shutter_to_manual",
"mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan.tidy_up_zebra_after_gridscan",
autospec=True,
)
def test_full_plan_tidies_at_end(
Expand Down Expand Up @@ -214,7 +215,7 @@ def test_full_plan_tidies_at_end(
autospec=True,
)
@patch(
"mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan.set_zebra_shutter_to_manual",
"mx_bluesky.hyperion.experiment_plans.flyscan_xray_centre_plan.tidy_up_zebra_after_gridscan",
autospec=True,
)
def test_full_plan_tidies_at_end_when_plan_fails(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ def test_remote_callbacks_write_to_dev_ispyb_for_rotation(
robot,
aperture_scatterguard,
fake_create_devices,
sample_shutter,
):
test_wl = 0.71
test_bs_x = 0.023
Expand All @@ -230,6 +231,7 @@ def test_remote_callbacks_write_to_dev_ispyb_for_rotation(
zebra=fake_create_devices["zebra"],
robot=robot,
oav=fake_create_devices["oav"],
sample_shutter=sample_shutter,
)

with patch("bluesky.preprocessors.__read_and_stash_a_motor", fake_read):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
)

from mx_bluesky.hyperion.device_setup_plans.setup_zebra import (
set_zebra_shutter_to_manual,
setup_zebra_for_gridscan,
setup_zebra_for_rotation,
tidy_up_zebra_after_gridscan,
)


Expand Down Expand Up @@ -42,6 +42,6 @@ async def test_zebra_set_up_for_rotation(RE, connected_zebra: Zebra):

@pytest.mark.s03
async def test_zebra_cleanup(RE, connected_zebra: Zebra):
RE(set_zebra_shutter_to_manual(connected_zebra, wait=True))
RE(tidy_up_zebra_after_gridscan(connected_zebra, wait=True))
assert await connected_zebra.output.out_pvs[TTL_DETECTOR].get_value() == PC_PULSE
assert await connected_zebra.output.out_pvs[TTL_SHUTTER].get_value() == OR1
Loading
Loading