mx-bluesky 1.4.7__py3-none-any.whl → 1.4.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. mx_bluesky/_version.py +2 -2
  2. mx_bluesky/beamlines/i04/redis_to_murko_forwarder.py +4 -4
  3. mx_bluesky/beamlines/i04/thawing_plan.py +8 -2
  4. mx_bluesky/beamlines/i23/__init__.py +3 -0
  5. mx_bluesky/beamlines/i23/serial.py +71 -0
  6. mx_bluesky/beamlines/i24/serial/__init__.py +2 -0
  7. mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +7 -2
  8. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/pumpprobe-py3v1.edl +3 -3
  9. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +6 -56
  10. mx_bluesky/beamlines/i24/serial/log.py +9 -10
  11. mx_bluesky/beamlines/i24/serial/parameters/utils.py +36 -7
  12. mx_bluesky/beamlines/i24/serial/setup_beamline/pv.py +0 -1
  13. mx_bluesky/beamlines/i24/serial/setup_beamline/pv_abstract.py +4 -4
  14. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +4 -4
  15. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +2 -1
  16. mx_bluesky/beamlines/i24/serial/web_gui_plans/general_plans.py +71 -11
  17. mx_bluesky/beamlines/i24/serial/write_nexus.py +3 -3
  18. mx_bluesky/{hyperion → common}/device_setup_plans/check_beamstop.py +1 -1
  19. mx_bluesky/{hyperion → common}/device_setup_plans/manipulate_sample.py +1 -1
  20. mx_bluesky/{hyperion → common}/device_setup_plans/setup_oav.py +12 -6
  21. mx_bluesky/{hyperion → common}/experiment_plans/change_aperture_then_move_plan.py +4 -5
  22. mx_bluesky/{hyperion → common}/experiment_plans/oav_grid_detection_plan.py +6 -6
  23. mx_bluesky/common/external_interaction/callbacks/common/ispyb_callback_base.py +6 -5
  24. mx_bluesky/common/external_interaction/callbacks/xray_centre/ispyb_callback.py +16 -47
  25. mx_bluesky/common/external_interaction/ispyb/ispyb_store.py +4 -1
  26. mx_bluesky/common/external_interaction/ispyb/ispyb_utils.py +4 -4
  27. mx_bluesky/common/parameters/components.py +22 -2
  28. mx_bluesky/common/parameters/constants.py +4 -16
  29. mx_bluesky/common/parameters/gridscan.py +36 -32
  30. mx_bluesky/common/plans/common_flyscan_xray_centre_plan.py +316 -0
  31. mx_bluesky/common/plans/inner_plans/__init__ .py +0 -0
  32. mx_bluesky/common/plans/read_hardware.py +3 -3
  33. mx_bluesky/common/utils/log.py +15 -12
  34. mx_bluesky/hyperion/__main__.py +2 -15
  35. mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +4 -4
  36. mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +0 -33
  37. mx_bluesky/hyperion/device_setup_plans/utils.py +4 -4
  38. mx_bluesky/hyperion/experiment_plans/__init__.py +0 -6
  39. mx_bluesky/hyperion/experiment_plans/experiment_registry.py +0 -9
  40. mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +71 -88
  41. mx_bluesky/hyperion/experiment_plans/hyperion_flyscan_xray_centre_plan.py +183 -0
  42. mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +12 -7
  43. mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +28 -7
  44. mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +4 -4
  45. mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +1 -1
  46. mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +11 -3
  47. mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +9 -8
  48. mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +18 -56
  49. mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +2 -2
  50. mx_bluesky/hyperion/external_interaction/agamemnon.py +62 -70
  51. mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +8 -6
  52. mx_bluesky/hyperion/external_interaction/callbacks/snapshot_callback.py +183 -31
  53. mx_bluesky/hyperion/parameters/cli.py +2 -10
  54. mx_bluesky/hyperion/parameters/constants.py +0 -5
  55. mx_bluesky/hyperion/parameters/device_composites.py +40 -5
  56. mx_bluesky/hyperion/parameters/gridscan.py +9 -58
  57. mx_bluesky/hyperion/parameters/rotation.py +0 -4
  58. mx_bluesky/hyperion/utils/context.py +2 -5
  59. mx_bluesky/hyperion/utils/validation.py +13 -10
  60. {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.8.dist-info}/METADATA +5 -4
  61. {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.8.dist-info}/RECORD +69 -65
  62. {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.8.dist-info}/WHEEL +1 -1
  63. mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +0 -467
  64. /mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/{short1-laser.png → s1l.png} +0 -0
  65. /mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/{short2-laser.png → s2l.png} +0 -0
  66. /mx_bluesky/{hyperion → common}/device_setup_plans/position_detector.py +0 -0
  67. /mx_bluesky/common/plans/{do_fgs.py → inner_plans/do_fgs.py} +0 -0
  68. {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.8.dist-info}/entry_points.txt +0 -0
  69. {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.8.dist-info}/licenses/LICENSE +0 -0
  70. {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.8.dist-info}/top_level.txt +0 -0
mx_bluesky/_version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '1.4.7'
21
- __version_tuple__ = version_tuple = (1, 4, 7)
20
+ __version__ = version = '1.4.8'
21
+ __version_tuple__ = version_tuple = (1, 4, 8)
@@ -6,7 +6,7 @@ from typing import TypedDict
6
6
 
7
7
  import numpy as np
8
8
  import zmq
9
- from dodal.beamlines.i04 import MURKO_REDIS_DB, REDIS_HOST, REDIS_PASSWORD
9
+ from dodal.devices.i04.constants import RedisConstants
10
10
  from numpy.typing import NDArray
11
11
  from PIL import Image
12
12
  from redis import StrictRedis
@@ -139,9 +139,9 @@ class RedisListener:
139
139
 
140
140
  def __init__(
141
141
  self,
142
- redis_host=REDIS_HOST,
143
- redis_password=REDIS_PASSWORD,
144
- db=MURKO_REDIS_DB,
142
+ redis_host=RedisConstants.REDIS_HOST,
143
+ redis_password=RedisConstants.REDIS_PASSWORD,
144
+ db=RedisConstants.MURKO_REDIS_DB,
145
145
  redis_channel="murko",
146
146
  ):
147
147
  self.redis_client = StrictRedis(
@@ -4,8 +4,8 @@ import bluesky.plan_stubs as bps
4
4
  import bluesky.preprocessors as bpp
5
5
  from bluesky.preprocessors import run_decorator, subs_decorator
6
6
  from bluesky.utils import MsgGenerator
7
- from dodal.beamlines.i04 import MURKO_REDIS_DB, REDIS_HOST, REDIS_PASSWORD
8
7
  from dodal.common import inject
8
+ from dodal.devices.i04.constants import RedisConstants
9
9
  from dodal.devices.oav.oav_detector import OAV
10
10
  from dodal.devices.oav.oav_to_redis_forwarder import OAVToRedisForwarder, Source
11
11
  from dodal.devices.robot import BartRobot
@@ -42,7 +42,13 @@ def thaw_and_stream_to_redis(
42
42
  beam_centre_i = yield from bps.rd(oav.beam_centre_i)
43
43
  beam_centre_j = yield from bps.rd(oav.beam_centre_j)
44
44
 
45
- @subs_decorator(MurkoCallback(REDIS_HOST, REDIS_PASSWORD, MURKO_REDIS_DB))
45
+ @subs_decorator(
46
+ MurkoCallback(
47
+ RedisConstants.REDIS_HOST,
48
+ RedisConstants.REDIS_PASSWORD,
49
+ RedisConstants.MURKO_REDIS_DB,
50
+ )
51
+ )
46
52
  @run_decorator(
47
53
  md={
48
54
  "microns_per_x_pixel": microns_per_pixel_x,
@@ -0,0 +1,3 @@
1
+ from mx_bluesky.beamlines.i23.serial import serial_collection
2
+
3
+ __all__ = ["serial_collection"]
@@ -0,0 +1,71 @@
1
+ from functools import partial
2
+
3
+ from bluesky import plan_stubs as bps
4
+ from bluesky.plans import rel_grid_scan
5
+ from bluesky.utils import short_uid
6
+ from dodal.beamlines.i23 import I23DetectorPositions
7
+ from dodal.common import inject
8
+ from dodal.devices.motors import SixAxisGonio
9
+ from dodal.devices.positioner import Positioner1D
10
+ from ophyd_async.epics.motor import Motor
11
+
12
+
13
+ def set_axis_to_max_velocity(axis: Motor):
14
+ max_vel = yield from bps.rd(axis.max_velocity)
15
+ yield from bps.mv(axis.velocity, max_vel)
16
+
17
+
18
+ def one_nd_step(
19
+ detectors,
20
+ step,
21
+ pos_cache,
22
+ omega_axis: Motor,
23
+ omega_rotation: float,
24
+ omega_velocity: float,
25
+ ):
26
+ def move():
27
+ yield from bps.checkpoint()
28
+ grp = short_uid("set")
29
+ for motor, pos in step.items():
30
+ yield from bps.abs_set(motor, pos, group=grp)
31
+ yield from set_axis_to_max_velocity(omega_axis)
32
+ yield from bps.abs_set(omega_axis, 0, group=grp)
33
+ yield from bps.wait(group=grp)
34
+
35
+ yield from move()
36
+ yield from bps.mv(omega_axis.velocity, omega_velocity)
37
+ yield from bps.mv(omega_axis, omega_rotation)
38
+
39
+
40
+ def serial_collection(
41
+ x_steps: int,
42
+ y_steps: int,
43
+ x_step_size: float,
44
+ y_step_size: float,
45
+ omega_rotation: float,
46
+ omega_velocity: float,
47
+ detector_motion: Positioner1D = inject("detector_motion"),
48
+ gonio: SixAxisGonio = inject("gonio"),
49
+ ):
50
+ """This plan runs a software controlled serial collection. i.e it moves in a snaked
51
+ grid and does a small rotation collection at each point."""
52
+
53
+ yield from bps.mv(detector_motion.stage_position, I23DetectorPositions.IN)
54
+ yield from rel_grid_scan(
55
+ [],
56
+ gonio.y,
57
+ 0,
58
+ y_step_size * (y_steps - 1),
59
+ y_steps,
60
+ gonio.x,
61
+ 0,
62
+ x_step_size * (x_steps - 1),
63
+ x_steps,
64
+ per_step=partial( # type: ignore
65
+ one_nd_step,
66
+ omega_axis=gonio.omega,
67
+ omega_rotation=omega_rotation,
68
+ omega_velocity=omega_velocity,
69
+ ),
70
+ snake_axes=True,
71
+ )
@@ -1,5 +1,6 @@
1
1
  from mx_bluesky.beamlines.i24.serial.web_gui_plans.general_plans import (
2
2
  gui_gonio_move_on_click,
3
+ gui_move_backlight,
3
4
  gui_move_detector,
4
5
  gui_set_parameters,
5
6
  gui_sleep,
@@ -57,4 +58,5 @@ __all__ = [
57
58
  "gui_sleep",
58
59
  "gui_move_detector",
59
60
  "gui_set_parameters",
61
+ "gui_move_backlight",
60
62
  ]
@@ -317,6 +317,7 @@ def main_extruder_plan(
317
317
  parameters.num_images,
318
318
  parameters.exposure_time_s,
319
319
  ],
320
+ dcm,
320
321
  )
321
322
  yield from setup_zebra_for_extruder_with_pump_probe_plan(
322
323
  zebra,
@@ -338,6 +339,7 @@ def main_extruder_plan(
338
339
  parameters.num_images,
339
340
  parameters.exposure_time_s,
340
341
  ],
342
+ dcm,
341
343
  )
342
344
  yield from setup_zebra_for_quickshot_plan(
343
345
  zebra, parameters.exposure_time_s, parameters.num_images, wait=True
@@ -441,6 +443,7 @@ def tidy_up_at_collection_end_plan(
441
443
  shutter: HutchShutter,
442
444
  parameters: ExtruderParameters,
443
445
  dcid: DCID,
446
+ dcm: DCM,
444
447
  ) -> MsgGenerator:
445
448
  """A plan to tidy up at the end of a collection, successful or aborted.
446
449
 
@@ -455,7 +458,7 @@ def tidy_up_at_collection_end_plan(
455
458
  if parameters.detector_name == "pilatus":
456
459
  yield from sup.pilatus("return-to-normal", None)
457
460
  elif parameters.detector_name == "eiger":
458
- yield from sup.eiger("return-to-normal", None)
461
+ yield from sup.eiger("return-to-normal", None, dcm)
459
462
  SSX_LOGGER.debug(f"{parameters.filename}_{caget(pv.eiger_seqID)}")
460
463
  SSX_LOGGER.debug("End of Run")
461
464
  SSX_LOGGER.info("Close hutch shutter")
@@ -534,7 +537,9 @@ def run_extruder_plan(
534
537
  )
535
538
  ),
536
539
  final_plan=lambda: (
537
- yield from tidy_up_at_collection_end_plan(zebra, shutter, parameters, dcid)
540
+ yield from tidy_up_at_collection_end_plan(
541
+ zebra, shutter, parameters, dcid, dcm
542
+ )
538
543
  ),
539
544
  auto_raise=False,
540
545
  )
@@ -1521,7 +1521,7 @@ x 275
1521
1521
  y 111
1522
1522
  w 175
1523
1523
  h 139
1524
- file "SCRIPTS_LOCATION/fixed_target/FT-gui-edm/short1-laser.png"
1524
+ file "SCRIPTS_LOCATION/fixed_target/FT-gui-edm/s1l.png"
1525
1525
  endObjectProperties
1526
1526
 
1527
1527
  # (PNG Image)
@@ -1534,7 +1534,7 @@ x 486
1534
1534
  y 111
1535
1535
  w 172
1536
1536
  h 139
1537
- file "SCRIPTS_LOCATION/fixed_target/FT-gui-edm/short2-laser.png"
1537
+ file "SCRIPTS_LOCATION/fixed_target/FT-gui-edm/s2l.png"
1538
1538
  endObjectProperties
1539
1539
 
1540
1540
  # (Static Text)
@@ -1600,7 +1600,7 @@ x 695
1600
1600
  y 111
1601
1601
  w 175
1602
1602
  h 139
1603
- file "SCRIPTS_LOCATION/fixed_target/FT-gui-edm/short1-laser.png"
1603
+ file "SCRIPTS_LOCATION/fixed_target/FT-gui-edm/s1l.png"
1604
1604
  endObjectProperties
1605
1605
 
1606
1606
  # (Static Text)
@@ -4,6 +4,7 @@ Fixed target data collection
4
4
 
5
5
  from datetime import datetime
6
6
  from pathlib import Path
7
+ from traceback import format_exception
7
8
 
8
9
  import bluesky.plan_stubs as bps
9
10
  import bluesky.preprocessors as bpp
@@ -51,52 +52,6 @@ from mx_bluesky.beamlines.i24.serial.setup_beamline.setup_zebra_plans import (
51
52
  )
52
53
  from mx_bluesky.beamlines.i24.serial.write_nexus import call_nexgen
53
54
 
54
- # Move this in common place as part of
55
- # https://github.com/DiamondLightSource/mx-bluesky/pull/603
56
- PMAC_MOVE_TIME = 0.008 # Move time between positions on chip ~ 7-8 ms
57
-
58
-
59
- def calculate_collection_timeout(parameters: FixedTargetParameters) -> float:
60
- """Give an estimation of the time the plan should wait for the data collection \
61
- to be finished.
62
-
63
- For non-pump probe collections and collection with short delays, it should be \
64
- enough to use the collection time plus a genereous 30s buffer.
65
- For EAVA (Excite and visit again) collections instead, the laser dwell and laser \
66
- delay times should be included in the calculation. For long dalays between pump \
67
- and probe, the shutter opening time will also need to be taken into account.
68
- For more details on the dynamics see
69
- https://confluence.diamond.ac.uk/display/MXTech/Dynamics+and+fixed+targets.
70
-
71
- Args:
72
- parameters (FixedTargerParameters): The collection parameters.
73
-
74
- Returns:
75
- The estimated collection time, in s.
76
- """
77
- buffer = PMAC_MOVE_TIME * parameters.total_num_images + 600
78
- pump_setting = parameters.pump_repeat
79
- collection_time = parameters.total_num_images * parameters.exposure_time_s
80
- if pump_setting in [
81
- PumpProbeSetting.NoPP,
82
- PumpProbeSetting.Short1,
83
- PumpProbeSetting.Short2,
84
- ]:
85
- timeout = collection_time + buffer
86
- else:
87
- # EAVA: Excite and visit again
88
- num_windows = parameters.total_num_images / parameters.num_exposures
89
- timeout = (
90
- collection_time
91
- + parameters.laser_dwell_s * num_windows # type: ignore
92
- + parameters.laser_delay_s
93
- + buffer
94
- )
95
- if pump_setting == PumpProbeSetting.Medium1:
96
- # Long delay between pump and probe, with fast shutter opening and closing.
97
- timeout = timeout + SHUTTER_OPEN_TIME * parameters.total_num_images
98
- return timeout
99
-
100
55
 
101
56
  def write_userlog(
102
57
  parameters: FixedTargetParameters,
@@ -430,6 +385,7 @@ def start_i24(
430
385
  parameters.total_num_images,
431
386
  parameters.exposure_time_s,
432
387
  ],
388
+ dcm,
433
389
  )
434
390
 
435
391
  # DCID process depends on detector PVs being set up already
@@ -505,7 +461,7 @@ def finish_i24(
505
461
  elif parameters.detector_name == "eiger":
506
462
  SSX_LOGGER.debug("Finish I24 Eiger")
507
463
  yield from reset_zebra_when_collection_done_plan(zebra)
508
- yield from sup.eiger("return-to-normal", None)
464
+ yield from sup.eiger("return-to-normal", None, dcm)
509
465
  complete_filename = cagetstring(pv.eiger_ODfilenameRBV) # type: ignore
510
466
  else:
511
467
  raise ValueError(f"{parameters.detector_name=} unrecognised")
@@ -520,12 +476,12 @@ def finish_i24(
520
476
  write_userlog(parameters, complete_filename, transmission, wavelength)
521
477
 
522
478
 
523
- def run_aborted_plan(pmac: PMAC, dcid: DCID):
479
+ def run_aborted_plan(pmac: PMAC, dcid: DCID, exception: Exception):
524
480
  """Plan to send pmac_strings to tell the PMAC when a collection has been aborted, \
525
481
  either by pressing the Abort button or because of a timeout, and to reset the \
526
482
  P variable.
527
483
  """
528
- SSX_LOGGER.warning("Data Collection Aborted")
484
+ SSX_LOGGER.warning(f"Data Collection Aborted: {format_exception(exception)}")
529
485
  yield from bps.trigger(pmac.abort_program, wait=True)
530
486
 
531
487
  end_time = datetime.now()
@@ -621,12 +577,6 @@ def kickoff_and_complete_collection(pmac: PMAC, parameters: FixedTargetParameter
621
577
  parameters.chip.chip_type, parameters.map_type, parameters.pump_repeat
622
578
  )
623
579
  yield from bps.abs_set(pmac.program_number, prog_num, group="setup_pmac")
624
- # Calculate approx collection time
625
- total_collection_time = calculate_collection_timeout(parameters)
626
- SSX_LOGGER.info(f"Estimated collection time: {total_collection_time}s.")
627
- yield from bps.abs_set(
628
- pmac.collection_time, total_collection_time, group="setup_pmac"
629
- )
630
580
  yield from bps.wait(group="setup_pmac") # Make sure the soft signals are set
631
581
 
632
582
  @bpp.run_decorator(md={"subplan_name": "run_ft_collection"})
@@ -731,7 +681,7 @@ def run_fixed_target_plan(
731
681
  parameters,
732
682
  dcid,
733
683
  ),
734
- except_plan=lambda e: (yield from run_aborted_plan(pmac, dcid)),
684
+ except_plan=lambda e: (yield from run_aborted_plan(pmac, dcid, e)),
735
685
  final_plan=lambda: (
736
686
  yield from tidy_up_after_collection_plan(
737
687
  zebra, pmac, shutter, dcm, parameters, dcid
@@ -99,16 +99,6 @@ def config(
99
99
  dev_mode (bool, optional): If true, will log to graylog on localhost instead \
100
100
  of production. Defaults to False.
101
101
  """
102
- do_default_logging_setup(
103
- "mx-bluesky.log",
104
- DEFAULT_GRAYLOG_PORT,
105
- dev_mode=dev_mode,
106
- integrate_all_logs=False,
107
- )
108
- # Remove dodal StreamHandler to avoid duplication of messages above debug
109
- dodal_logger.removeHandler(dodal_logger.handlers[0])
110
- _integrate_bluesky_logs(dodal_logger)
111
-
112
102
  if logfile:
113
103
  logs = _get_logging_file_path() / logfile
114
104
  fileFormatter = logging.Formatter(
@@ -119,6 +109,15 @@ def config(
119
109
  FH.setLevel(logging.DEBUG)
120
110
  FH.setFormatter(fileFormatter)
121
111
  SSX_LOGGER.addHandler(FH)
112
+ do_default_logging_setup(
113
+ "mx-bluesky.log",
114
+ DEFAULT_GRAYLOG_PORT,
115
+ dev_mode=dev_mode,
116
+ integrate_all_logs=False,
117
+ )
118
+ # Remove dodal StreamHandler to avoid duplication of messages above debug
119
+ dodal_logger.removeHandler(dodal_logger.handlers[0])
120
+ _integrate_bluesky_logs(dodal_logger)
122
121
 
123
122
 
124
123
  def log_on_entry(func):
@@ -1,4 +1,5 @@
1
- from typing import Any
1
+ from collections.abc import Sequence
2
+ from typing import Any, Literal
2
3
 
3
4
  from mx_bluesky.beamlines.i24.serial.fixed_target.ft_utils import ChipType
4
5
  from mx_bluesky.beamlines.i24.serial.parameters.experiment_parameters import (
@@ -13,8 +14,27 @@ class EmptyMapError(Exception):
13
14
  pass
14
15
 
15
16
 
16
- def get_chip_format(chip_type: ChipType) -> ChipDescription:
17
- """Default parameter values."""
17
+ def get_chip_format(
18
+ chip_type: ChipType,
19
+ format: Sequence[int | float] | None = None,
20
+ origin: Literal["edm", "web"] = "edm",
21
+ ) -> ChipDescription:
22
+ """Get the default parameter values for the requested chip type.
23
+
24
+ For an Oxford-type chip, the default values are hard coded as the dimensions are
25
+ always the same. For a Custom chip instead, the number of steps and step size in
26
+ each direction must be entered through the GUI - web or edm. If the collection is
27
+ run through the edm, the values will be read from the general purpose PVs set on
28
+ there. If instead the plan is run from the web UI, the values will be passed in the
29
+ form of a list/tuple of 4 values.
30
+
31
+ Args:
32
+ chip_type (ChipType): Chip in use
33
+ custom_format (Sequence[int | float], optional): Number and size of steps input
34
+ from the web ui. Format should be: [int, int, float, float].
35
+ Defaults to None.
36
+ origin (str, optional): UI in use, can be either web or edm. Defaults to edm.
37
+ """
18
38
  defaults: dict[str, int | float] = {}
19
39
  match chip_type:
20
40
  case ChipType.Oxford:
@@ -33,10 +53,19 @@ def get_chip_format(chip_type: ChipType) -> ChipDescription:
33
53
  defaults["x_blocks"] = defaults["y_blocks"] = 1
34
54
  defaults["b2b_horz"] = defaults["b2b_vert"] = 0.0
35
55
  case ChipType.Custom:
36
- defaults["x_num_steps"] = int(caget(pv.me14e_gp6))
37
- defaults["y_num_steps"] = int(caget(pv.me14e_gp7))
38
- defaults["x_step_size"] = float(caget(pv.me14e_gp8))
39
- defaults["y_step_size"] = float(caget(pv.me14e_gp99))
56
+ if origin == "edm":
57
+ defaults["x_num_steps"] = int(caget(pv.me14e_gp6))
58
+ defaults["y_num_steps"] = int(caget(pv.me14e_gp7))
59
+ defaults["x_step_size"] = float(caget(pv.me14e_gp8))
60
+ defaults["y_step_size"] = float(caget(pv.me14e_gp99))
61
+ else:
62
+ # NOTE Test for WEB GUI
63
+ if not format:
64
+ raise ValueError("Format for custom chip not passed")
65
+ defaults["x_num_steps"] = format[0]
66
+ defaults["y_num_steps"] = format[1]
67
+ defaults["x_step_size"] = format[2]
68
+ defaults["y_step_size"] = format[3]
40
69
  defaults["x_blocks"] = defaults["y_blocks"] = 1
41
70
  defaults["b2b_horz"] = defaults["b2b_vert"] = 0.0
42
71
  case ChipType.MISP:
@@ -154,7 +154,6 @@ dcm_gap = "BL24I-MO-DCM-01:GAP"
154
154
  dcm_roll1 = "BL24I-MO-DCM-01:XTAL1:ROLL"
155
155
  dcm_roll2 = "BL24I-MO-DCM-01:XTAL2:ROLL"
156
156
  dcm_pitch2 = "BL24I-MO-DCM-01:XTAL2:PITCH"
157
- dcm_lambda = "BL24I-MO-DCM-01:LAMBDA"
158
157
  dcm_energy = "BL24I-MO-DCM-01:ENERGY"
159
158
 
160
159
  # S2
@@ -19,8 +19,8 @@ class Pilatus:
19
19
  round(a * b, 3) for a, b in zip(image_size_pixels, pixel_size_mm, strict=False)
20
20
  )
21
21
 
22
- det_y_threshold = 560.0
23
- det_y_target = 566.0
22
+ det_y_threshold = 640.0
23
+ det_y_target = 647.0
24
24
 
25
25
  class pv:
26
26
  detector_distance = pv.pilat_detdist
@@ -48,8 +48,8 @@ class Eiger:
48
48
  round(a * b, 3) for a, b in zip(image_size_pixels, pixel_size_mm, strict=False)
49
49
  )
50
50
 
51
- det_y_threshold = -10.0
52
- det_y_target = -22.0
51
+ det_y_threshold = 70.0
52
+ det_y_target = 59.0
53
53
 
54
54
  class pv:
55
55
  detector_distance = pv.eiger_detdist
@@ -6,6 +6,7 @@ from dodal.devices.detector.det_dim_constants import DetectorSizeConstants
6
6
  from dodal.devices.i24.aperture import Aperture, AperturePositions
7
7
  from dodal.devices.i24.beam_center import DetectorBeamCenter
8
8
  from dodal.devices.i24.beamstop import Beamstop, BeamstopPositions
9
+ from dodal.devices.i24.dcm import DCM
9
10
  from dodal.devices.i24.dual_backlight import BacklightPositions, DualBacklight
10
11
  from dodal.devices.i24.i24_detector_motion import DetectorMotion
11
12
  from dodal.devices.util.lookup_tables import (
@@ -289,7 +290,6 @@ def pilatus(action, args_list):
289
290
  for arg in args_list:
290
291
  SSX_LOGGER.debug(f"Argument: {arg}")
291
292
 
292
- # caput(pv.pilat_wavelength, caget(pv.dcm_lambda))
293
293
  caput(pv.pilat_detdist, caget(pv.det_z))
294
294
  caput(pv.pilat_filtertrasm, caget(pv.attn_match))
295
295
 
@@ -377,15 +377,15 @@ def pilatus(action, args_list):
377
377
  return 0
378
378
 
379
379
 
380
- def eiger(action, args_list):
380
+ def eiger(action, args_list, dcm: DCM):
381
381
  SSX_LOGGER.debug("***** Entering Eiger")
382
382
  SSX_LOGGER.info(f"Setup eiger - {action}")
383
383
  if args_list:
384
384
  for arg in args_list:
385
385
  SSX_LOGGER.debug(f"Argument: {arg}")
386
- # caput(pv.eiger_wavelength, caget(pv.dcm_lambda))
387
386
  caput(pv.eiger_detdist, str(float(caget(pv.det_z)) / 1000))
388
- caput(pv.eiger_wavelength, caget(pv.dcm_lambda))
387
+ dcm_wavelength_a = yield from bps.rd(dcm.wavelength_in_a.user_readback)
388
+ caput(pv.eiger_wavelength, dcm_wavelength_a)
389
389
  caput(pv.eiger_omegaincr, 0.0)
390
390
  yield from bps.sleep(0.1)
391
391
  # Setup common to all collections ###
@@ -13,7 +13,7 @@ from dodal.devices.i24.i24_detector_motion import DetectorMotion
13
13
  from mx_bluesky.beamlines.i24.serial.log import SSX_LOGGER
14
14
  from mx_bluesky.beamlines.i24.serial.parameters import SSXType
15
15
  from mx_bluesky.beamlines.i24.serial.setup_beamline import pv
16
- from mx_bluesky.beamlines.i24.serial.setup_beamline.ca import caget
16
+ from mx_bluesky.beamlines.i24.serial.setup_beamline.ca import caget, caput
17
17
  from mx_bluesky.beamlines.i24.serial.setup_beamline.pv_abstract import (
18
18
  Detector,
19
19
  Eiger,
@@ -93,4 +93,5 @@ def setup_detector_stage(
93
93
  Eiger.det_y_target if requested_detector == "eiger" else Pilatus.det_y_target
94
94
  )
95
95
  yield from _move_detector_stage(detector_stage, det_y_target)
96
+ caput(det_type_pv, requested_detector)
96
97
  SSX_LOGGER.info("Detector setup done.")
@@ -5,6 +5,11 @@ import bluesky.plan_stubs as bps
5
5
  import bluesky.preprocessors as bpp
6
6
  from blueapi.core import MsgGenerator
7
7
  from dodal.beamlines import i24
8
+ from dodal.common import inject
9
+ from dodal.devices.i24.dual_backlight import BacklightPositions, DualBacklight
10
+ from dodal.devices.i24.i24_detector_motion import DetectorMotion
11
+ from dodal.devices.i24.pmac import PMAC
12
+ from dodal.devices.oav.oav_detector import OAV
8
13
 
9
14
  from mx_bluesky.beamlines.i24.serial.fixed_target.ft_utils import (
10
15
  ChipType,
@@ -14,11 +19,15 @@ from mx_bluesky.beamlines.i24.serial.fixed_target.ft_utils import (
14
19
  from mx_bluesky.beamlines.i24.serial.fixed_target.i24ssx_moveonclick import (
15
20
  _move_on_mouse_click_plan,
16
21
  )
17
- from mx_bluesky.beamlines.i24.serial.log import _read_visit_directory_from_file
22
+ from mx_bluesky.beamlines.i24.serial.log import (
23
+ SSX_LOGGER,
24
+ _read_visit_directory_from_file,
25
+ )
18
26
  from mx_bluesky.beamlines.i24.serial.parameters import (
19
27
  FixedTargetParameters,
20
28
  get_chip_format,
21
29
  )
30
+ from mx_bluesky.beamlines.i24.serial.parameters.utils import EmptyMapError
22
31
  from mx_bluesky.beamlines.i24.serial.setup_beamline import pv
23
32
  from mx_bluesky.beamlines.i24.serial.setup_beamline.ca import caput
24
33
  from mx_bluesky.beamlines.i24.serial.setup_beamline.pv_abstract import Eiger, Pilatus
@@ -29,9 +38,18 @@ from mx_bluesky.beamlines.i24.serial.setup_beamline.setup_detector import (
29
38
 
30
39
 
31
40
  @bpp.run_decorator()
32
- def gui_stage_move_on_click(position_px: tuple[int, int]) -> MsgGenerator:
33
- oav = i24.oav()
34
- pmac = i24.pmac()
41
+ def gui_move_backlight(
42
+ position: str, backlight: DualBacklight = inject("backlight")
43
+ ) -> MsgGenerator:
44
+ bl_pos = BacklightPositions(position)
45
+ yield from bps.abs_set(backlight, bl_pos, wait=True)
46
+ SSX_LOGGER.debug(f"Backlight moved to {bl_pos.value}")
47
+
48
+
49
+ @bpp.run_decorator()
50
+ def gui_stage_move_on_click(
51
+ position_px: tuple[int, int], oav: OAV = inject("oav"), pmac: PMAC = inject("pmac")
52
+ ) -> MsgGenerator:
35
53
  yield from _move_on_mouse_click_plan(oav, pmac, position_px)
36
54
 
37
55
 
@@ -58,11 +76,14 @@ def gui_sleep(sec: int) -> MsgGenerator:
58
76
 
59
77
 
60
78
  @bpp.run_decorator()
61
- def gui_move_detector(det: Literal["eiger", "pilatus"]) -> MsgGenerator:
62
- detector_stage = i24.detector_motion()
79
+ def gui_move_detector(
80
+ det: Literal["eiger", "pilatus"],
81
+ detector_stage: DetectorMotion = inject("detector_motion"),
82
+ ) -> MsgGenerator:
63
83
  det_y_target = Eiger.det_y_target if det == "eiger" else Pilatus.det_y_target
64
84
  yield from _move_detector_stage(detector_stage, det_y_target)
65
85
  # Make the output readable
86
+ SSX_LOGGER.debug(f"Detector move done, resetting general PV to {det}")
66
87
  caput(pv.me14e_gp101, det)
67
88
 
68
89
 
@@ -75,16 +96,55 @@ def gui_set_parameters(
75
96
  transmission: float,
76
97
  n_shots: int,
77
98
  chip_type: str,
99
+ map_type: str,
100
+ chip_format: list[int | float], # for Lite Oxford it's the chipmap
78
101
  checker_pattern: bool,
79
102
  pump_probe: str,
80
103
  laser_dwell: float,
81
104
  laser_delay: float,
82
105
  pre_pump: float,
83
106
  ) -> MsgGenerator:
107
+ """Set the parameter model for the data collection.
108
+
109
+ Args:
110
+ sub_dir (str): subdirectory of the visit to write data in.
111
+ chip_name (str): a name identifying the current chip collection, will be used
112
+ as filename.
113
+ exp_time (float): exposure time of each window shot, in s.
114
+ det_dist (float): sample-detector distance, in mm.
115
+ transmission (float): requested beam intensity transmission, expressed as
116
+ a fraction, e.g. 0.3.
117
+ n_shots (int): number of times each window should be collected.
118
+ chip_type (str): type of chip in use.
119
+ map_type (str): if an Oxford chip is used, define whether it's a full chip
120
+ collection or lite mapping is in use. For all other chip, this will be None.
121
+ chip_format (list[int|float]): for a custom chip, a list of the number of x,y
122
+ steps and the x,y step size. For an Oxford chip, the list should be empty
123
+ if collecting a full chip and a list of the block numbers to scan for a
124
+ lite collection.
125
+ checker_pattern (bool): whether checker_pattern is turned on, ie. only every
126
+ other window in a block gets collected
127
+ pump_probe (str): pump probe setting.
128
+ laser_dwell (float): laser exposure time for pump probe collections, in s.
129
+ laser_delay (float): delay between laser exposure and collection, in s.
130
+ pre_pump (float): pre-pump exposure time for a pump probe short2 collection,
131
+ ie a pump-in-probe where the collection starts during the pump.
132
+ """
84
133
  # NOTE still a work in progress, adding to it as the ui grows
134
+ # See progression of https://github.com/DiamondLightSource/mx-daq-ui/issues/3
85
135
  detector_stage = i24.detector_motion()
86
136
  det_type = yield from get_detector_type(detector_stage)
87
- chip_params = get_chip_format(ChipType[chip_type])
137
+ _format = chip_format if ChipType[chip_type] is ChipType.Custom else None
138
+ chip_params = get_chip_format(ChipType[chip_type], _format)
139
+ if ChipType[chip_type] in [ChipType.Oxford, ChipType.OxfordInner]:
140
+ mapping = MappingType.Lite if map_type == "Lite" else MappingType.NoMap
141
+ if mapping is MappingType.Lite and len(chip_format) == 0:
142
+ # this logic should go in the gui with error message.
143
+ raise EmptyMapError("No blocks chosen")
144
+ chip_map = chip_format
145
+ else:
146
+ mapping = MappingType.NoMap
147
+ chip_map = []
88
148
 
89
149
  params = {
90
150
  "visit": _read_visit_directory_from_file().as_posix(), # noqa
@@ -96,14 +156,14 @@ def gui_set_parameters(
96
156
  "num_exposures": n_shots,
97
157
  "transmission": transmission,
98
158
  "chip": chip_params,
99
- "map_type": MappingType.NoMap,
100
- "chip_map": [],
159
+ "map_type": mapping,
160
+ "chip_map": chip_map,
101
161
  "pump_repeat": PumpProbeSetting[pump_probe], # pump_repeat,
102
162
  "laser_dwell_s": laser_dwell,
103
163
  "laser_delay_s": laser_delay,
104
164
  "checker_pattern": checker_pattern,
105
165
  "pre_pump_exposure_s": pre_pump,
106
166
  }
107
- print(FixedTargetParameters(**params))
108
- # This will then run the run_fixed_target plan
167
+ # TODO run the run_fixed_target plan once params are set (GUI not ready yet)
109
168
  yield from bps.sleep(0.5)
169
+ return FixedTargetParameters(**params)