mx-bluesky 1.4.7__py3-none-any.whl → 1.4.9__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 (89) hide show
  1. mx_bluesky/_version.py +2 -2
  2. mx_bluesky/beamlines/aithre_lasershaping/__init__.py +8 -0
  3. mx_bluesky/beamlines/aithre_lasershaping/beamline_safe.py +36 -0
  4. mx_bluesky/beamlines/aithre_lasershaping/goniometer_controls.py +43 -0
  5. mx_bluesky/beamlines/i04/redis_to_murko_forwarder.py +4 -4
  6. mx_bluesky/beamlines/i04/thawing_plan.py +8 -2
  7. mx_bluesky/beamlines/i23/__init__.py +3 -0
  8. mx_bluesky/beamlines/i23/serial.py +71 -0
  9. mx_bluesky/beamlines/i24/serial/__init__.py +2 -0
  10. mx_bluesky/beamlines/i24/serial/blueapi_config.yaml +2 -1
  11. mx_bluesky/beamlines/i24/serial/dcid.py +5 -5
  12. mx_bluesky/beamlines/i24/serial/extruder/EX-gui-edm/DetStage.edl +2 -2
  13. mx_bluesky/beamlines/i24/serial/extruder/EX-gui-edm/DiamondExtruder-I24-py3v1.edl +9 -9
  14. mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +25 -5
  15. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DetStage.edl +2 -2
  16. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/DiamondChipI24-py3v1.edl +14 -14
  17. mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/pumpprobe-py3v1.edl +5 -5
  18. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +29 -60
  19. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +7 -1
  20. mx_bluesky/beamlines/i24/serial/log.py +9 -10
  21. mx_bluesky/beamlines/i24/serial/parameters/utils.py +36 -7
  22. mx_bluesky/beamlines/i24/serial/setup_beamline/pv.py +0 -1
  23. mx_bluesky/beamlines/i24/serial/setup_beamline/pv_abstract.py +4 -4
  24. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +4 -12
  25. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +2 -1
  26. mx_bluesky/beamlines/i24/serial/web_gui_plans/general_plans.py +71 -11
  27. mx_bluesky/beamlines/i24/serial/write_nexus.py +3 -3
  28. mx_bluesky/{hyperion → common}/device_setup_plans/manipulate_sample.py +6 -14
  29. mx_bluesky/{hyperion → common}/device_setup_plans/setup_oav.py +12 -6
  30. mx_bluesky/{hyperion → common}/experiment_plans/change_aperture_then_move_plan.py +4 -5
  31. mx_bluesky/{hyperion → common}/experiment_plans/oav_grid_detection_plan.py +6 -6
  32. mx_bluesky/common/external_interaction/callbacks/common/ispyb_callback_base.py +6 -5
  33. mx_bluesky/common/external_interaction/callbacks/xray_centre/ispyb_callback.py +16 -47
  34. mx_bluesky/common/external_interaction/ispyb/ispyb_store.py +4 -1
  35. mx_bluesky/common/external_interaction/ispyb/ispyb_utils.py +4 -4
  36. mx_bluesky/common/external_interaction/nexus/nexus_utils.py +2 -2
  37. mx_bluesky/common/parameters/components.py +22 -2
  38. mx_bluesky/common/parameters/constants.py +4 -16
  39. mx_bluesky/common/parameters/gridscan.py +36 -32
  40. mx_bluesky/common/plans/common_flyscan_xray_centre_plan.py +316 -0
  41. mx_bluesky/common/plans/inner_plans/__init__ .py +0 -0
  42. mx_bluesky/common/plans/read_hardware.py +3 -3
  43. mx_bluesky/common/utils/log.py +19 -15
  44. mx_bluesky/hyperion/__main__.py +6 -24
  45. mx_bluesky/hyperion/baton_handler.py +8 -3
  46. mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +4 -4
  47. mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +0 -33
  48. mx_bluesky/hyperion/device_setup_plans/smargon.py +2 -7
  49. mx_bluesky/hyperion/device_setup_plans/utils.py +6 -5
  50. mx_bluesky/hyperion/experiment_plans/__init__.py +1 -7
  51. mx_bluesky/hyperion/experiment_plans/experiment_registry.py +3 -13
  52. mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +80 -87
  53. mx_bluesky/hyperion/experiment_plans/hyperion_flyscan_xray_centre_plan.py +183 -0
  54. mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +50 -15
  55. mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +31 -7
  56. mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +4 -4
  57. mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +1 -1
  58. mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +13 -14
  59. mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +9 -8
  60. mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +30 -71
  61. mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +2 -2
  62. mx_bluesky/hyperion/external_interaction/agamemnon.py +78 -80
  63. mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +8 -6
  64. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +3 -3
  65. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_mapping.py +6 -3
  66. mx_bluesky/hyperion/external_interaction/callbacks/rotation/nexus_callback.py +2 -2
  67. mx_bluesky/hyperion/external_interaction/callbacks/snapshot_callback.py +183 -31
  68. mx_bluesky/hyperion/external_interaction/config_server.py +4 -1
  69. mx_bluesky/hyperion/parameters/cli.py +4 -19
  70. mx_bluesky/hyperion/parameters/constants.py +1 -5
  71. mx_bluesky/hyperion/parameters/device_composites.py +40 -5
  72. mx_bluesky/hyperion/parameters/gridscan.py +9 -58
  73. mx_bluesky/hyperion/parameters/load_centre_collect.py +4 -4
  74. mx_bluesky/hyperion/parameters/rotation.py +9 -12
  75. mx_bluesky/hyperion/utils/context.py +2 -2
  76. mx_bluesky/hyperion/utils/validation.py +15 -19
  77. {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.9.dist-info}/METADATA +7 -6
  78. {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.9.dist-info}/RECORD +86 -83
  79. {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.9.dist-info}/WHEEL +1 -1
  80. mx_bluesky/common/external_interaction/test_config_server.py +0 -38
  81. mx_bluesky/hyperion/device_setup_plans/check_beamstop.py +0 -27
  82. mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +0 -467
  83. /mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/{short1-laser.png → s1l.png} +0 -0
  84. /mx_bluesky/beamlines/i24/serial/fixed_target/FT-gui-edm/{short2-laser.png → s2l.png} +0 -0
  85. /mx_bluesky/{hyperion → common}/device_setup_plans/position_detector.py +0 -0
  86. /mx_bluesky/common/plans/{do_fgs.py → inner_plans/do_fgs.py} +0 -0
  87. {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.9.dist-info}/entry_points.txt +0 -0
  88. {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.9.dist-info}/licenses/LICENSE +0 -0
  89. {mx_bluesky-1.4.7.dist-info → mx_bluesky-1.4.9.dist-info}/top_level.txt +0 -0
@@ -4,7 +4,7 @@ major 4
4
4
  minor 0
5
5
  release 1
6
6
  x 830
7
- y 200
7
+ y 237
8
8
  w 900
9
9
  h 700
10
10
  font "arial-medium-r-18.0"
@@ -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)
@@ -1585,7 +1585,7 @@ symbol0 {
1585
1585
  1 "ML"
1586
1586
  }
1587
1587
  value0 {
1588
- 0 "none"
1588
+ 0 "False"
1589
1589
  1 "True"
1590
1590
  }
1591
1591
  endObjectProperties
@@ -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
@@ -18,6 +19,7 @@ from dodal.devices.i24.dcm import DCM
18
19
  from dodal.devices.i24.dual_backlight import DualBacklight
19
20
  from dodal.devices.i24.focus_mirrors import FocusMirrorsMode
20
21
  from dodal.devices.i24.i24_detector_motion import DetectorMotion
22
+ from dodal.devices.i24.pilatus_metadata import PilatusMetadata
21
23
  from dodal.devices.i24.pmac import PMAC
22
24
  from dodal.devices.zebra.zebra import Zebra
23
25
 
@@ -37,7 +39,10 @@ from mx_bluesky.beamlines.i24.serial.fixed_target.i24ssx_Chip_Manager_py3v1 impo
37
39
  )
38
40
  from mx_bluesky.beamlines.i24.serial.log import SSX_LOGGER, log_on_entry
39
41
  from mx_bluesky.beamlines.i24.serial.parameters import FixedTargetParameters
40
- from mx_bluesky.beamlines.i24.serial.parameters.constants import BEAM_CENTER_LUT_FILES
42
+ from mx_bluesky.beamlines.i24.serial.parameters.constants import (
43
+ BEAM_CENTER_LUT_FILES,
44
+ DetectorName,
45
+ )
41
46
  from mx_bluesky.beamlines.i24.serial.setup_beamline import caget, cagetstring, caput, pv
42
47
  from mx_bluesky.beamlines.i24.serial.setup_beamline import setup_beamline as sup
43
48
  from mx_bluesky.beamlines.i24.serial.setup_beamline.setup_zebra_plans import (
@@ -51,52 +56,6 @@ from mx_bluesky.beamlines.i24.serial.setup_beamline.setup_zebra_plans import (
51
56
  )
52
57
  from mx_bluesky.beamlines.i24.serial.write_nexus import call_nexgen
53
58
 
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
59
 
101
60
  def write_userlog(
102
61
  parameters: FixedTargetParameters,
@@ -225,10 +184,12 @@ def load_motion_program_data(
225
184
  # Pump setting chosen
226
185
  prefix = 14
227
186
  SSX_LOGGER.info(f"Setting program prefix to {prefix}")
228
- yield from bps.abs_set(pmac.pmac_string, "P1439=0", wait=True)
229
187
  if checker_pattern:
230
188
  SSX_LOGGER.info("Checker pattern setting enabled.")
231
189
  yield from bps.abs_set(pmac.pmac_string, "P1439=1", wait=True)
190
+ else:
191
+ SSX_LOGGER.info("Checker pattern setting disabled.")
192
+ yield from bps.abs_set(pmac.pmac_string, "P1439=0", wait=True)
232
193
  if pump_repeat == PumpProbeSetting.Medium1:
233
194
  # Medium1 has time delays (Fast shutter opening time in ms)
234
195
  yield from bps.abs_set(pmac.pmac_string, "P1441=50", wait=True)
@@ -315,6 +276,7 @@ def start_i24(
315
276
  mirrors: FocusMirrorsMode,
316
277
  beam_center_device: DetectorBeamCenter,
317
278
  dcid: DCID,
279
+ pilatus_metadata: PilatusMetadata,
318
280
  ):
319
281
  """Set up for I24 fixed target data collection, trigger the detector and open \
320
282
  the hutch shutter.
@@ -373,7 +335,9 @@ def start_i24(
373
335
 
374
336
  # DCID process depends on detector PVs being set up already
375
337
  SSX_LOGGER.debug("Start DCID process")
376
- filetemplate = yield from get_pilatus_filename_template_from_device()
338
+ filetemplate = yield from get_pilatus_filename_template_from_device(
339
+ pilatus_metadata
340
+ )
377
341
  dcid.generate_dcid(
378
342
  beam_settings=beam_settings,
379
343
  image_dir=filepath,
@@ -430,6 +394,7 @@ def start_i24(
430
394
  parameters.total_num_images,
431
395
  parameters.exposure_time_s,
432
396
  ],
397
+ dcm,
433
398
  )
434
399
 
435
400
  # DCID process depends on detector PVs being set up already
@@ -505,7 +470,7 @@ def finish_i24(
505
470
  elif parameters.detector_name == "eiger":
506
471
  SSX_LOGGER.debug("Finish I24 Eiger")
507
472
  yield from reset_zebra_when_collection_done_plan(zebra)
508
- yield from sup.eiger("return-to-normal", None)
473
+ yield from sup.eiger("return-to-normal", None, dcm)
509
474
  complete_filename = cagetstring(pv.eiger_ODfilenameRBV) # type: ignore
510
475
  else:
511
476
  raise ValueError(f"{parameters.detector_name=} unrecognised")
@@ -520,12 +485,12 @@ def finish_i24(
520
485
  write_userlog(parameters, complete_filename, transmission, wavelength)
521
486
 
522
487
 
523
- def run_aborted_plan(pmac: PMAC, dcid: DCID):
488
+ def run_aborted_plan(pmac: PMAC, dcid: DCID, exception: Exception):
524
489
  """Plan to send pmac_strings to tell the PMAC when a collection has been aborted, \
525
490
  either by pressing the Abort button or because of a timeout, and to reset the \
526
491
  P variable.
527
492
  """
528
- SSX_LOGGER.warning("Data Collection Aborted")
493
+ SSX_LOGGER.warning(f"Data Collection Aborted: {format_exception(exception)}")
529
494
  yield from bps.trigger(pmac.abort_program, wait=True)
530
495
 
531
496
  end_time = datetime.now()
@@ -546,6 +511,7 @@ def main_fixed_target_plan(
546
511
  beam_center_device: DetectorBeamCenter,
547
512
  parameters: FixedTargetParameters,
548
513
  dcid: DCID,
514
+ pilatus_metadata: PilatusMetadata,
549
515
  ) -> MsgGenerator:
550
516
  SSX_LOGGER.info("Running a chip collection on I24")
551
517
 
@@ -590,6 +556,7 @@ def main_fixed_target_plan(
590
556
  mirrors,
591
557
  beam_center_device,
592
558
  dcid,
559
+ pilatus_metadata,
593
560
  )
594
561
 
595
562
  SSX_LOGGER.info("Moving to Start")
@@ -621,12 +588,6 @@ def kickoff_and_complete_collection(pmac: PMAC, parameters: FixedTargetParameter
621
588
  parameters.chip.chip_type, parameters.map_type, parameters.pump_repeat
622
589
  )
623
590
  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
591
  yield from bps.wait(group="setup_pmac") # Make sure the soft signals are set
631
592
 
632
593
  @bpp.run_decorator(md={"subplan_name": "run_ft_collection"})
@@ -699,6 +660,9 @@ def run_fixed_target_plan(
699
660
  dcm: DCM = inject("dcm"),
700
661
  mirrors: FocusMirrorsMode = inject("focus_mirrors"),
701
662
  attenuator: ReadOnlyAttenuator = inject("attenuator"),
663
+ beam_center_eiger: DetectorBeamCenter = inject("eiger_bc"),
664
+ beam_center_pilatus: DetectorBeamCenter = inject("pilatus_bc"),
665
+ pilatus_metadata: PilatusMetadata = inject("pilatus_meta"),
702
666
  ) -> MsgGenerator:
703
667
  # Read the parameters
704
668
  parameters: FixedTargetParameters = yield from read_parameters(
@@ -711,7 +675,11 @@ def run_fixed_target_plan(
711
675
  if parameters.chip_map:
712
676
  yield from upload_chip_map_to_geobrick(pmac, parameters.chip_map)
713
677
 
714
- beam_center_device = sup.get_beam_center_device(parameters.detector_name)
678
+ beam_center_device = (
679
+ beam_center_eiger
680
+ if parameters.detector_name is DetectorName.EIGER
681
+ else beam_center_pilatus
682
+ )
715
683
 
716
684
  # DCID instance - do not create yet
717
685
  dcid = DCID(emit_errors=False, expt_params=parameters)
@@ -730,8 +698,9 @@ def run_fixed_target_plan(
730
698
  beam_center_device,
731
699
  parameters,
732
700
  dcid,
701
+ pilatus_metadata,
733
702
  ),
734
- except_plan=lambda e: (yield from run_aborted_plan(pmac, dcid)),
703
+ except_plan=lambda e: (yield from run_aborted_plan(pmac, dcid, e)),
735
704
  final_plan=lambda: (
736
705
  yield from tidy_up_after_collection_plan(
737
706
  zebra, pmac, shutter, dcm, parameters, dcid
@@ -113,6 +113,12 @@ def initialise_stages(
113
113
  yield from bps.wait(group=group)
114
114
 
115
115
 
116
+ def _is_checker_pattern() -> bool:
117
+ """Read the checker pattern value and return True if selected."""
118
+ checks = int(caget(pv.me14e_gp111))
119
+ return bool(checks)
120
+
121
+
116
122
  @log_on_entry
117
123
  def read_parameters(
118
124
  detector_stage: DetectorMotion,
@@ -172,7 +178,7 @@ def read_parameters(
172
178
  "chip": chip_params.model_dump(),
173
179
  "map_type": map_type,
174
180
  "pump_repeat": pump_repeat,
175
- "checker_pattern": bool(caget(pv.me14e_gp111)),
181
+ "checker_pattern": _is_checker_pattern(),
176
182
  "chip_map": chip_map,
177
183
  "laser_dwell_s": float(caget(pv.me14e_gp103)) if pump_repeat != 0 else 0.0,
178
184
  "laser_delay_s": float(caget(pv.me14e_gp110)) if pump_repeat != 0 else 0.0,
@@ -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
@@ -1,11 +1,11 @@
1
1
  from pathlib import Path
2
2
 
3
3
  import bluesky.plan_stubs as bps
4
- from dodal.beamlines import i24
5
4
  from dodal.devices.detector.det_dim_constants import DetectorSizeConstants
6
5
  from dodal.devices.i24.aperture import Aperture, AperturePositions
7
6
  from dodal.devices.i24.beam_center import DetectorBeamCenter
8
7
  from dodal.devices.i24.beamstop import Beamstop, BeamstopPositions
8
+ from dodal.devices.i24.dcm import DCM
9
9
  from dodal.devices.i24.dual_backlight import BacklightPositions, DualBacklight
10
10
  from dodal.devices.i24.i24_detector_motion import DetectorMotion
11
11
  from dodal.devices.util.lookup_tables import (
@@ -18,13 +18,6 @@ from mx_bluesky.beamlines.i24.serial.setup_beamline import pv
18
18
  from mx_bluesky.beamlines.i24.serial.setup_beamline.ca import caget, caput
19
19
 
20
20
 
21
- def get_beam_center_device(detector_in_use: str) -> DetectorBeamCenter:
22
- if detector_in_use == "eiger":
23
- return i24.eiger_beam_center(connect_immediately=True)
24
- else:
25
- return i24.pilatus_beam_center(connect_immediately=True)
26
-
27
-
28
21
  def compute_beam_center_position_from_lut(
29
22
  lut_path: Path,
30
23
  detector_distance_mm: float,
@@ -289,7 +282,6 @@ def pilatus(action, args_list):
289
282
  for arg in args_list:
290
283
  SSX_LOGGER.debug(f"Argument: {arg}")
291
284
 
292
- # caput(pv.pilat_wavelength, caget(pv.dcm_lambda))
293
285
  caput(pv.pilat_detdist, caget(pv.det_z))
294
286
  caput(pv.pilat_filtertrasm, caget(pv.attn_match))
295
287
 
@@ -377,15 +369,15 @@ def pilatus(action, args_list):
377
369
  return 0
378
370
 
379
371
 
380
- def eiger(action, args_list):
372
+ def eiger(action, args_list, dcm: DCM):
381
373
  SSX_LOGGER.debug("***** Entering Eiger")
382
374
  SSX_LOGGER.info(f"Setup eiger - {action}")
383
375
  if args_list:
384
376
  for arg in args_list:
385
377
  SSX_LOGGER.debug(f"Argument: {arg}")
386
- # caput(pv.eiger_wavelength, caget(pv.dcm_lambda))
387
378
  caput(pv.eiger_detdist, str(float(caget(pv.det_z)) / 1000))
388
- caput(pv.eiger_wavelength, caget(pv.dcm_lambda))
379
+ dcm_wavelength_a = yield from bps.rd(dcm.wavelength_in_a.user_readback)
380
+ caput(pv.eiger_wavelength, dcm_wavelength_a)
389
381
  caput(pv.eiger_omegaincr, 0.0)
390
382
  yield from bps.sleep(0.1)
391
383
  # 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)
@@ -21,7 +21,7 @@ def call_nexgen(
21
21
  parameters: ExtruderParameters | FixedTargetParameters,
22
22
  wavelength_in_a: float,
23
23
  beam_center_in_pix: tuple[float, float],
24
- start_time: datetime | None = None,
24
+ start_time: datetime,
25
25
  ):
26
26
  """Call the nexus writer by sending a request to nexgen-server.
27
27
 
@@ -32,7 +32,7 @@ def call_nexgen(
32
32
  parameters (SerialAndLaserExperiment): Collection parameters.
33
33
  wavelength_in_a (float): Wavelength, in A.
34
34
  beam_center_in_pix (list[float]): Beam center position on detector, in pixels.
35
- start_time (datetime, optional): Collection start time.
35
+ start_time (datetime): Collection start time.
36
36
 
37
37
  Raises:
38
38
  ValueError: For a wrong experiment type passed (either unknwon or not matched \
@@ -96,7 +96,7 @@ def call_nexgen(
96
96
  "visitpath": os.fspath(meta_h5.parent),
97
97
  "wavelength": wavelength_in_a,
98
98
  "bit_depth": bit_depth,
99
- "start_time": start_time,
99
+ "start_time": start_time.isoformat(),
100
100
  }
101
101
  SSX_LOGGER.info(f"Sending POST request to {url} with payload:")
102
102
  SSX_LOGGER.info(pprint.pformat(payload))