Skip to content
This repository has been archived by the owner on Sep 2, 2024. It is now read-only.

Use new params in rotation scan plan #1326

Merged
merged 5 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
22 changes: 22 additions & 0 deletions src/hyperion/device_setup_plans/manipulate_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,25 @@ def move_x_y_z(
yield from bps.abs_set(smargon.z, z, group=group)
if wait:
yield from bps.wait(group)


def move_phi_chi_omega(
smargon: Smargon,
phi: float | None = None,
chi: float | None = None,
omega: float | None = None,
wait=False,
group="move_phi_chi_omega",
):
"""Move the x, y, and z axes of the given smargon to the specified position. All
axes are optional."""

LOGGER.info(f"Moving smargon to phi, chi, omega: {(phi, chi, omega)}")
if phi:
yield from bps.abs_set(smargon.phi, phi, group=group)
if chi:
yield from bps.abs_set(smargon.chi, chi, group=group)
if omega:
yield from bps.abs_set(smargon.omega, omega, group=group)
if wait:
yield from bps.wait(group)
79 changes: 36 additions & 43 deletions src/hyperion/experiment_plans/rotation_scan_plan.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from __future__ import annotations

import dataclasses
from typing import Any, Union

import bluesky.plan_stubs as bps
import bluesky.preprocessors as bpp
Expand All @@ -10,7 +9,6 @@
from dodal.devices.attenuator import Attenuator
from dodal.devices.backlight import Backlight
from dodal.devices.dcm import DCM
from dodal.devices.detector import DetectorParams
from dodal.devices.detector.detector_motion import DetectorMotion
from dodal.devices.eiger import EigerDetector
from dodal.devices.flux import Flux
Expand All @@ -24,6 +22,7 @@

from hyperion.device_setup_plans.manipulate_sample import (
cleanup_sample_environment,
move_phi_chi_omega,
move_x_y_z,
setup_sample_environment,
)
Expand All @@ -41,10 +40,6 @@
)
from hyperion.log import LOGGER
from hyperion.parameters.constants import CONST
from hyperion.parameters.plan_specific.rotation_scan_internal_params import (
RotationInternalParameters,
RotationScanParams,
)
from hyperion.parameters.rotation import RotationScan
from hyperion.utils.context import device_composite_from_context

Expand Down Expand Up @@ -101,8 +96,7 @@ class RotationMotionProfile:


def calculate_motion_profile(
detector_params: DetectorParams,
expt_params: RotationScanParams,
params: RotationScan,
motor_time_to_speed_s: float,
max_velocity_deg_s: float,
) -> RotationMotionProfile:
Expand All @@ -114,19 +108,19 @@ def calculate_motion_profile(
See https://github.com/DiamondLightSource/hyperion/wiki/rotation-scan-geometry
for a simple pictorial explanation."""

direction = ROTATION_DIRECTION[expt_params.rotation_direction]
num_images = expt_params.get_num_images()
shutter_time_s = expt_params.shutter_opening_time_s
image_width_deg = detector_params.omega_increment
exposure_time_s = detector_params.exposure_time
direction = ROTATION_DIRECTION[params.rotation_direction]
num_images = params.num_images
shutter_time_s = params.shutter_opening_time_s
image_width_deg = params.rotation_increment_deg
exposure_time_s = params.exposure_time_s
motor_time_to_speed_s *= ACCELERATION_MARGIN
start_scan_deg = detector_params.omega_start
start_scan_deg = params.omega_start_deg

LOGGER.info("Calculating rotation scan motion profile:")
LOGGER.info(
f"{num_images=}, {shutter_time_s=}, {image_width_deg=}, {exposure_time_s=}, {direction=}"
)
LOGGER.info(f"{(scan_width_deg := num_images * detector_params.omega_increment)=}")
LOGGER.info(f"{(scan_width_deg := num_images * params.rotation_increment_deg)=}")
LOGGER.info(f"{(speed_for_rotation_deg_s := image_width_deg / exposure_time_s)=}")
LOGGER.info(
f"{(acceleration_offset_deg := motor_time_to_speed_s * speed_for_rotation_deg_s)=}"
Expand All @@ -135,7 +129,7 @@ def calculate_motion_profile(
f"{(start_motion_deg := start_scan_deg - (acceleration_offset_deg * direction))=}"
)
LOGGER.info(
f"{(shutter_opening_deg := speed_for_rotation_deg_s * expt_params.shutter_opening_time_s)=}"
f"{(shutter_opening_deg := speed_for_rotation_deg_s * shutter_time_s)=}"
)
LOGGER.info(f"{(total_exposure_s := num_images * exposure_time_s)=}")
LOGGER.info(
Expand All @@ -147,7 +141,7 @@ def calculate_motion_profile(
start_motion_deg=start_motion_deg,
scan_width_deg=scan_width_deg,
shutter_time_s=shutter_time_s,
direction=expt_params.rotation_direction,
direction=params.rotation_direction,
speed_for_rotation_deg_s=speed_for_rotation_deg_s,
acceleration_offset_deg=acceleration_offset_deg,
shutter_opening_deg=shutter_opening_deg,
Expand All @@ -159,7 +153,7 @@ def calculate_motion_profile(

def rotation_scan_plan(
composite: RotationScanComposite,
params: RotationInternalParameters,
params: RotationScan,
motion_values: RotationMotionProfile,
):
"""A plan to collect diffraction images from a sample continuously rotating about
Expand All @@ -170,8 +164,8 @@ def rotation_scan_plan(
@bpp.run_decorator(
md={
"subplan_name": CONST.PLAN.ROTATION_MAIN,
"zocalo_environment": params.hyperion_params.zocalo_environment,
"scan_points": [params.get_scan_points()],
"zocalo_environment": params.zocalo_environment,
"scan_points": [params.scan_points],
}
)
def _rotation_scan_plan(
Expand All @@ -188,7 +182,7 @@ def _rotation_scan_plan(
yield from bps.abs_set(
axis,
motion_values.start_motion_deg,
group="move_to_start",
group="move_to_rotation_start",
wait=True,
)
yield from setup_zebra_for_rotation(
Expand All @@ -205,8 +199,8 @@ def _rotation_scan_plan(
LOGGER.info("Wait for any previous moves...")
# wait for all the setup tasks at once
yield from bps.wait("setup_senv")
yield from bps.wait("move_x_y_z")
yield from bps.wait("move_to_start")
yield from bps.wait("move_gonio_to_start")
yield from bps.wait("move_to_rotation_start")
yield from bps.wait("setup_zebra")

# get some information for the ispyb deposition and trigger the callback
Expand Down Expand Up @@ -253,62 +247,61 @@ def cleanup_plan(composite: RotationScanComposite, max_vel: float, **kwargs):

def rotation_scan(
composite: RotationScanComposite,
parameters: Union[RotationScan, RotationInternalParameters, Any],
parameters: RotationScan,
) -> MsgGenerator:
old_parameters = (
parameters
if isinstance(parameters, RotationInternalParameters)
else parameters.old_parameters()
)

@bpp.set_run_key_decorator("rotation_scan")
@bpp.run_decorator( # attach experiment metadata to the start document
md={
"subplan_name": CONST.PLAN.ROTATION_OUTER,
CONST.TRIGGER.ZOCALO: CONST.PLAN.ROTATION_MAIN,
"hyperion_internal_parameters": parameters.json(),
"hyperion_internal_parameters": parameters.old_parameters().json(),
"activate_callbacks": [
"RotationISPyBCallback",
"RotationNexusFileCallback",
],
}
)
def rotation_scan_plan_with_stage_and_cleanup(
params: RotationInternalParameters,
params: RotationScan,
):
motor_time_to_speed = yield from bps.rd(composite.smargon.omega.acceleration)
max_vel = (
yield from bps.rd(composite.smargon.omega.max_velocity)
or DEFAULT_MAX_VELOCITY
)
motion_values = calculate_motion_profile(
params.hyperion_params.detector_params,
params.experiment_params,
params,
motor_time_to_speed,
max_vel,
)

eiger: EigerDetector = composite.eiger
eiger.set_detector_parameters(params.hyperion_params.detector_params)
eiger.set_detector_parameters(params.detector_params)

@bpp.stage_decorator([eiger])
@bpp.finalize_decorator(lambda: cleanup_plan(composite, max_vel))
def rotation_with_cleanup_and_stage(params: RotationInternalParameters):
def rotation_with_cleanup_and_stage(params: RotationScan):
LOGGER.info("setting up sample environment...")
yield from setup_sample_environment(
composite.detector_motion,
composite.backlight,
composite.attenuator,
params.experiment_params.transmission_fraction,
params.hyperion_params.detector_params.detector_distance,
params.transmission_frac,
params.detector_params.detector_distance,
)
LOGGER.info("moving to position (if specified)")
yield from move_x_y_z(
composite.smargon,
params.experiment_params.x,
params.experiment_params.y,
params.experiment_params.z,
group="move_x_y_z",
params.x_start_um,
params.y_start_um,
params.z_start_um,
group="move_gonio_to_start",
)
yield from move_phi_chi_omega(
composite.smargon,
params.phi_start_deg,
params.chi_start_deg,
group="move_gonio_to_start",
)
yield from rotation_scan_plan(
composite,
Expand All @@ -319,4 +312,4 @@ def rotation_with_cleanup_and_stage(params: RotationInternalParameters):
LOGGER.info("setting up and staging eiger...")
yield from rotation_with_cleanup_and_stage(params)

yield from rotation_scan_plan_with_stage_and_cleanup(old_parameters)
yield from rotation_scan_plan_with_stage_and_cleanup(parameters)
1 change: 0 additions & 1 deletion src/hyperion/parameters/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ class XyzAxis(str, Enum):
class HyperionParameters(BaseModel):
class Config:
arbitrary_types_allowed = True
use_enum_values = True
extra = Extra.forbid
json_encoders = {
ParameterVersion: lambda pv: str(pv),
Expand Down
12 changes: 5 additions & 7 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,7 @@
from hyperion.parameters.plan_specific.panda.panda_gridscan_internal_params import (
PandAGridscanInternalParameters,
)
from hyperion.parameters.plan_specific.rotation_scan_internal_params import (
RotationInternalParameters,
)
from hyperion.parameters.rotation import RotationScan

i03.DAQ_CONFIGURATION_PATH = "tests/test_data/test_daq_configuration"

Expand Down Expand Up @@ -240,18 +238,18 @@ def test_panda_fgs_params():

@pytest.fixture
def test_rotation_params():
return RotationInternalParameters(
return RotationScan(
**raw_params_from_file(
"tests/test_data/parameter_json_files/good_test_rotation_scan_parameters.json"
"tests/test_data/new_parameter_json_files/good_test_rotation_scan_parameters.json"
)
)


@pytest.fixture
def test_rotation_params_nomove():
return RotationInternalParameters(
return RotationScan(
**raw_params_from_file(
"tests/test_data/parameter_json_files/good_test_rotation_scan_parameters_nomove.json"
"tests/test_data/new_parameter_json_files/good_test_rotation_scan_parameters_nomove.json"
)
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"parameter_model_version": "5.0.0",
"comment": "test",
"det_dist_to_beam_converter_path": "tests/test_data/test_lookup_table.txt",
"storage_directory": "/tmp/dls/i03/data/2024/cm31105-4/auto/123456/",
"detector_distance_mm": 100.0,
"detector": "EIGER2_X_16M",
"demand_energy_ev": 100,
"exposure_time_s": 0.1,
"insertion_prefix": "SR03S",
"omega_start_deg": 0.0,
"file_name": "file_name",
"scan_width_deg": 180.0,
"rotation_axis": "omega",
"rotation_direction": "Negative",
"rotation_increment_deg": 0.1,
"run_number": 0,
"sample_id": 123456,
"shutter_opening_time_s": 0.6,
"visit": "cm31105-4",
"zocalo_environment": "dev_artemis",
"transmission_frac": 0.1,
"phi_start_deg": 0.47,
"chi_start_deg": 23.85,
"x_start_um": 1.0,
"y_start_um": 2.0,
"z_start_um": 3.0,
"ispyb_extras": {
"position": [
10.0,
20.0,
30.0
],
"xtal_snapshots_omega_start": [
"test_1_y",
"test_2_y",
"test_3_y"
],
"xtal_snapshots_omega_end": [
"test_1_z",
"test_2_z",
"test_3_z"
],
"xtal_snapshots": [
"test_1",
"test_2",
"test_3"
],
"beam_size_x": 1.0,
"beam_size_y": 1.0,
"focal_spot_size_x": 1.0,
"focal_spot_size_y": 1.0,
"resolution": 1.0
}
}
Loading
Loading