dls-dodal 1.68.0__py3-none-any.whl → 2.0.0__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.
- {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/METADATA +1 -31
- dls_dodal-2.0.0.dist-info/RECORD +354 -0
- {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/WHEEL +1 -1
- dodal/_version.py +2 -2
- dodal/beamlines/__init__.py +10 -17
- dodal/beamlines/adsim.py +40 -33
- dodal/beamlines/b01_1.py +11 -0
- dodal/beamlines/b07.py +17 -21
- dodal/beamlines/b07_1.py +20 -22
- dodal/beamlines/b07_shared.py +12 -0
- dodal/beamlines/b16.py +1 -1
- dodal/beamlines/b21.py +15 -6
- dodal/beamlines/i02_1.py +17 -45
- dodal/beamlines/i02_2.py +6 -12
- dodal/beamlines/i03.py +8 -5
- dodal/beamlines/i03_supervisor.py +19 -0
- dodal/beamlines/i04.py +87 -184
- dodal/beamlines/i05.py +9 -39
- dodal/beamlines/i05_1.py +4 -13
- dodal/beamlines/i05_shared.py +51 -0
- dodal/beamlines/i06_1.py +26 -0
- dodal/beamlines/{i06.py → i06_shared.py} +25 -14
- dodal/beamlines/i07.py +14 -16
- dodal/beamlines/i09.py +76 -29
- dodal/beamlines/i09_1.py +25 -56
- dodal/beamlines/i09_1_shared.py +61 -0
- dodal/beamlines/i09_2.py +6 -100
- dodal/beamlines/i09_2_shared.py +110 -0
- dodal/beamlines/i10.py +60 -54
- dodal/beamlines/i10_1.py +99 -10
- dodal/beamlines/{i10_optics.py → i10_shared.py} +80 -66
- dodal/beamlines/i11.py +31 -18
- dodal/beamlines/i13_1.py +1 -1
- dodal/beamlines/i15.py +6 -6
- dodal/beamlines/i15_1.py +6 -6
- dodal/beamlines/i16.py +11 -0
- dodal/beamlines/i17.py +37 -28
- dodal/beamlines/i18.py +3 -4
- dodal/beamlines/i19_1.py +95 -34
- dodal/beamlines/i19_2.py +68 -52
- dodal/beamlines/i19_optics.py +26 -13
- dodal/beamlines/i20_1.py +17 -11
- dodal/beamlines/i21.py +44 -29
- dodal/beamlines/i22.py +19 -4
- dodal/beamlines/i23.py +20 -27
- dodal/beamlines/i24.py +64 -113
- dodal/beamlines/k07.py +99 -5
- dodal/beamlines/p38.py +3 -3
- dodal/beamlines/p60.py +35 -14
- dodal/beamlines/p99.py +16 -15
- dodal/beamlines/training_rig.py +20 -12
- dodal/cli.py +36 -2
- dodal/common/__init__.py +2 -1
- dodal/common/beamlines/beamline_parameters.py +2 -1
- dodal/common/beamlines/beamline_utils.py +11 -9
- dodal/common/beamlines/commissioning_mode.py +6 -3
- dodal/common/coordination.py +12 -14
- dodal/common/crystal_metadata.py +5 -8
- dodal/common/device_utils.py +4 -3
- dodal/common/maths.py +87 -19
- dodal/common/udc_directory_provider.py +13 -8
- dodal/common/visit.py +18 -21
- dodal/common/watcher_utils.py +13 -12
- dodal/device_manager.py +94 -54
- dodal/devices/aperturescatterguard.py +26 -27
- dodal/devices/areadetector/plugins/cam.py +1 -3
- dodal/devices/areadetector/plugins/mjpg.py +6 -5
- dodal/devices/attenuator/attenuator.py +12 -11
- dodal/devices/beamlines/b07/__init__.py +3 -0
- dodal/devices/{b07_1 → beamlines/b07_1}/__init__.py +2 -2
- dodal/devices/{b07_1 → beamlines/b07_1}/ccmc.py +5 -10
- dodal/devices/{b16 → beamlines/b16}/detector.py +2 -3
- dodal/devices/{i02_1 → beamlines/i02_1}/fast_grid_scan.py +2 -3
- dodal/devices/{i02_1 → beamlines/i02_1}/sample_motors.py +1 -1
- dodal/devices/{i03 → beamlines/i03}/beamsize.py +11 -7
- dodal/devices/{i03 → beamlines/i03}/dcm.py +1 -2
- dodal/devices/{i03 → beamlines/i03}/undulator_dcm.py +4 -5
- dodal/devices/beamlines/i04/beam_centre.py +151 -0
- dodal/devices/{i04 → beamlines/i04}/beamsize.py +11 -7
- dodal/devices/beamlines/i04/max_pixel.py +25 -0
- dodal/devices/{i04 → beamlines/i04}/murko_results.py +23 -8
- dodal/devices/{i04 → beamlines/i04}/transfocator.py +10 -15
- dodal/devices/beamlines/i05/__init__.py +3 -0
- dodal/devices/beamlines/i06_shared/__init__.py +3 -0
- dodal/devices/beamlines/i06_shared/i06_enum.py +7 -0
- dodal/devices/{i07 → beamlines/i07}/dcm.py +2 -3
- dodal/devices/{i07 → beamlines/i07}/id.py +8 -9
- dodal/devices/beamlines/i09/__init__.py +3 -0
- dodal/devices/{i09_1_shared → beamlines/i09_1_shared}/hard_energy.py +5 -6
- dodal/devices/{i09_1_shared → beamlines/i09_1_shared}/hard_undulator_functions.py +19 -16
- dodal/devices/{i10 → beamlines/i10}/diagnostics.py +4 -3
- dodal/devices/{i10 → beamlines/i10}/i10_apple2.py +37 -51
- dodal/devices/{i10 → beamlines/i10}/rasor/rasor_current_amp.py +1 -24
- dodal/devices/{i10 → beamlines/i10}/rasor/rasor_motors.py +2 -2
- dodal/devices/{i10 → beamlines/i10}/slits.py +5 -3
- dodal/devices/beamlines/i10_1/__init__.py +9 -0
- dodal/devices/beamlines/i10_1/electromagnet/magnet.py +16 -0
- dodal/devices/beamlines/i10_1/electromagnet/stages.py +14 -0
- dodal/devices/beamlines/i10_1/scaler_cards.py +13 -0
- dodal/devices/{i11 → beamlines/i11}/cyberstar_blower.py +1 -1
- dodal/devices/{i11 → beamlines/i11}/diff_stages.py +4 -6
- dodal/devices/{i11 → beamlines/i11}/mythen.py +3 -4
- dodal/devices/{i11 → beamlines/i11}/nx100robot.py +6 -6
- dodal/devices/{i11 → beamlines/i11}/spinner.py +1 -1
- dodal/devices/{i13_1 → beamlines/i13_1}/merlin.py +1 -1
- dodal/devices/{i15 → beamlines/i15}/dcm.py +1 -2
- dodal/devices/{i15 → beamlines/i15}/focussing_mirror.py +5 -5
- dodal/devices/{i15 → beamlines/i15}/jack.py +2 -2
- dodal/devices/{i15 → beamlines/i15}/multilayer_mirror.py +1 -1
- dodal/devices/{i17 → beamlines/i17}/i17_apple2.py +16 -22
- dodal/devices/{i18 → beamlines/i18}/diode.py +1 -1
- dodal/devices/{i19 → beamlines/i19}/access_controlled/attenuator_motor_squad.py +12 -8
- dodal/devices/{i19 → beamlines/i19}/access_controlled/blueapi_device.py +16 -15
- dodal/devices/beamlines/i19/access_controlled/piezo_control.py +72 -0
- dodal/devices/{i19 → beamlines/i19}/access_controlled/shutter.py +11 -9
- dodal/devices/{i19 → beamlines/i19}/backlight.py +3 -1
- dodal/devices/{i19 → beamlines/i19}/mapt_configuration.py +2 -1
- dodal/devices/{i19 → beamlines/i19}/pin_col_stages.py +11 -8
- dodal/devices/beamlines/i19/pin_tip.py +32 -0
- dodal/devices/beamlines/i21/__init__.py +3 -0
- dodal/devices/{i22 → beamlines/i22}/dcm.py +1 -2
- dodal/devices/{i22 → beamlines/i22}/fswitch.py +1 -3
- dodal/devices/{i22 → beamlines/i22}/nxsas.py +5 -4
- dodal/devices/{i24 → beamlines/i24}/beam_center.py +1 -1
- dodal/devices/{i24 → beamlines/i24}/beamstop.py +2 -2
- dodal/devices/{i24 → beamlines/i24}/commissioning_jungfrau.py +12 -12
- dodal/devices/{i24 → beamlines/i24}/dcm.py +1 -3
- dodal/devices/{i24 → beamlines/i24}/dual_backlight.py +3 -3
- dodal/devices/{i24 → beamlines/i24}/pmac.py +9 -7
- dodal/devices/{p60 → beamlines/p60}/lab_xray_source.py +1 -1
- dodal/devices/beamlines/p99/__init__.py +0 -0
- dodal/devices/{p99 → beamlines/p99}/andor2_point.py +11 -15
- dodal/devices/bimorph_mirror.py +22 -20
- dodal/devices/collimation_table.py +3 -2
- dodal/devices/common_dcm.py +30 -20
- dodal/devices/controllers.py +2 -2
- dodal/devices/cryostream.py +8 -0
- dodal/devices/current_amplifiers/current_amplifier.py +16 -18
- dodal/devices/current_amplifiers/current_amplifier_detector.py +9 -10
- dodal/devices/current_amplifiers/femto.py +8 -9
- dodal/devices/current_amplifiers/sr570.py +16 -16
- dodal/devices/current_amplifiers/struck_scaler_counter.py +5 -5
- dodal/devices/detector/det_resolution.py +9 -8
- dodal/devices/detector/detector.py +4 -2
- dodal/devices/diamond_filter.py +3 -4
- dodal/devices/eiger.py +32 -17
- dodal/devices/eiger_odin.py +1 -1
- dodal/devices/electron_analyser/base/__init__.py +3 -3
- dodal/devices/electron_analyser/base/base_controller.py +32 -21
- dodal/devices/electron_analyser/base/base_detector.py +15 -20
- dodal/devices/electron_analyser/base/base_driver_io.py +39 -46
- dodal/devices/electron_analyser/base/base_enums.py +0 -5
- dodal/devices/electron_analyser/base/base_region.py +29 -31
- dodal/devices/electron_analyser/base/base_util.py +18 -16
- dodal/devices/electron_analyser/base/energy_sources.py +35 -40
- dodal/devices/electron_analyser/specs/specs_detector.py +7 -6
- dodal/devices/electron_analyser/vgscienta/vgscienta_detector.py +7 -6
- dodal/devices/eurotherm.py +3 -2
- dodal/devices/fast_grid_scan.py +31 -34
- dodal/devices/fast_shutter.py +125 -39
- dodal/devices/flux.py +1 -1
- dodal/devices/focusing_mirror.py +29 -11
- dodal/devices/hutch_shutter.py +6 -6
- dodal/devices/insertion_device/__init__.py +20 -8
- dodal/devices/insertion_device/apple2_controller.py +371 -0
- dodal/devices/insertion_device/apple2_undulator.py +184 -587
- dodal/devices/insertion_device/apple_knot_controller.py +222 -0
- dodal/devices/insertion_device/energy.py +161 -0
- dodal/devices/insertion_device/energy_motor_lookup.py +21 -28
- dodal/devices/insertion_device/lookup_table_models.py +47 -52
- dodal/devices/insertion_device/polarisation.py +36 -0
- dodal/devices/ipin.py +1 -1
- dodal/devices/linkam3.py +7 -5
- dodal/devices/motors.py +107 -19
- dodal/devices/mx_phase1/beamstop.py +2 -4
- dodal/devices/oav/oav_calculations.py +20 -13
- dodal/devices/oav/oav_detector.py +92 -22
- dodal/devices/oav/oav_parameters.py +4 -9
- dodal/devices/oav/oav_to_redis_forwarder.py +22 -18
- dodal/devices/oav/pin_image_recognition/__init__.py +4 -6
- dodal/devices/oav/pin_image_recognition/manual_test.py +1 -2
- dodal/devices/oav/pin_image_recognition/utils.py +30 -32
- dodal/devices/oav/snapshots/grid_overlay.py +10 -9
- dodal/devices/oav/snapshots/snapshot_image_processing.py +15 -13
- dodal/devices/oav/utils.py +20 -6
- dodal/devices/p45.py +3 -9
- dodal/devices/pgm.py +8 -14
- dodal/devices/pressure_jump_cell.py +93 -32
- dodal/devices/qbpm.py +1 -3
- dodal/devices/robot.py +45 -20
- dodal/devices/s4_slit_gaps.py +1 -1
- dodal/devices/selectable_source.py +41 -0
- dodal/devices/slits.py +2 -5
- dodal/devices/smargon.py +2 -3
- dodal/devices/temperture_controller/lakeshore/lakeshore.py +38 -64
- dodal/devices/temperture_controller/lakeshore/lakeshore_io.py +21 -35
- dodal/devices/tetramm.py +7 -7
- dodal/devices/turbo_slit.py +8 -7
- dodal/devices/undulator.py +42 -56
- dodal/devices/util/adjuster_plans.py +2 -3
- dodal/devices/util/epics_util.py +10 -10
- dodal/devices/util/lookup_tables.py +17 -18
- dodal/devices/v2f.py +2 -3
- dodal/devices/watsonmarlow323_pump.py +1 -1
- dodal/devices/xbpm_feedback.py +3 -2
- dodal/devices/xspress3/xspress3.py +8 -11
- dodal/devices/xspress3/xspress3_channel.py +3 -6
- dodal/devices/zebra/zebra.py +21 -7
- dodal/devices/zebra/zebra_constants_mapping.py +12 -7
- dodal/devices/zebra/zebra_controlled_shutter.py +2 -1
- dodal/devices/zocalo/zocalo_interaction.py +14 -14
- dodal/devices/zocalo/zocalo_results.py +33 -33
- dodal/log.py +23 -20
- dodal/plan_stubs/check_topup.py +15 -15
- dodal/plan_stubs/data_session.py +6 -6
- dodal/plan_stubs/motor_utils.py +22 -18
- dodal/plan_stubs/pressure_jump_cell.py +18 -0
- dodal/plan_stubs/wrapped.py +40 -55
- dodal/plans/bimorph.py +63 -52
- dodal/plans/configure_arm_trigger_and_disarm_detector.py +0 -1
- dodal/plans/device_setup_plans/__init__.py +5 -0
- dodal/plans/device_setup_plans/setup_pin_tip_params.py +63 -0
- dodal/plans/preprocessors/verify_undulator_gap.py +10 -8
- dodal/plans/spec_path.py +3 -5
- dodal/plans/verify_undulator_gap.py +1 -2
- dodal/plans/wrapped.py +4 -3
- dodal/testing/__init__.py +0 -0
- dodal/testing/electron_analyser/device_factory.py +5 -7
- dodal/testing/fixtures/devices/apple2.py +38 -0
- dodal/testing/fixtures/run_engine.py +3 -7
- dodal/testing/fixtures/utils.py +1 -2
- dodal/utils.py +60 -58
- dls_dodal-1.68.0.dist-info/RECORD +0 -330
- dodal/beamline_specific_utils/i05_shared.py +0 -14
- dodal/devices/b07/__init__.py +0 -3
- dodal/devices/i04/max_pixel.py +0 -38
- dodal/devices/i05/__init__.py +0 -3
- dodal/devices/i09/__init__.py +0 -3
- dodal/devices/i21/__init__.py +0 -5
- {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/licenses/LICENSE +0 -0
- {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/top_level.txt +0 -0
- /dodal/{beamline_specific_utils → devices/beamlines}/__init__.py +0 -0
- /dodal/devices/{b07 → beamlines/b07}/enums.py +0 -0
- /dodal/devices/{b07_1 → beamlines/b07_1}/enums.py +0 -0
- /dodal/devices/{b16 → beamlines/b16}/__init__.py +0 -0
- /dodal/devices/{i02_1 → beamlines/i02_1}/__init__.py +0 -0
- /dodal/devices/{i02_2 → beamlines/i02_2}/__init__.py +0 -0
- /dodal/devices/{i03 → beamlines/i03}/__init__.py +0 -0
- /dodal/devices/{i03 → beamlines/i03}/constants.py +0 -0
- /dodal/devices/{i04 → beamlines/i04}/__init__.py +0 -0
- /dodal/devices/{i04 → beamlines/i04}/constants.py +0 -0
- /dodal/devices/{i05 → beamlines/i05}/enums.py +0 -0
- /dodal/devices/{i07 → beamlines/i07}/__init__.py +0 -0
- /dodal/devices/{i09 → beamlines/i09}/enums.py +0 -0
- /dodal/devices/{i09_1 → beamlines/i09_1}/__init__.py +0 -0
- /dodal/devices/{i09_1 → beamlines/i09_1}/enums.py +0 -0
- /dodal/devices/{i09_1_shared → beamlines/i09_1_shared}/__init__.py +0 -0
- /dodal/devices/{i09_2_shared → beamlines/i09_2_shared}/__init__.py +0 -0
- /dodal/devices/{i09_2_shared → beamlines/i09_2_shared}/i09_apple2.py +0 -0
- /dodal/devices/{i10 → beamlines/i10}/__init__.py +0 -0
- /dodal/devices/{i10 → beamlines/i10}/i10_setting_data.py +0 -0
- /dodal/devices/{i10 → beamlines/i10}/mirrors.py +0 -0
- /dodal/devices/{i10 → beamlines/i10}/rasor/__init__.py +0 -0
- /dodal/devices/{i10 → beamlines/i10}/rasor/rasor_scaler_cards.py +0 -0
- /dodal/devices/{i11 → beamlines/i10_1/electromagnet}/__init__.py +0 -0
- /dodal/devices/{i13_1 → beamlines/i11}/__init__.py +0 -0
- /dodal/devices/{i15 → beamlines/i13_1}/__init__.py +0 -0
- /dodal/devices/{i13_1 → beamlines/i13_1}/merlin_controller.py +0 -0
- /dodal/devices/{i17 → beamlines/i15}/__init__.py +0 -0
- /dodal/devices/{i15 → beamlines/i15}/laue.py +0 -0
- /dodal/devices/{i15 → beamlines/i15}/motors.py +0 -0
- /dodal/devices/{i15 → beamlines/i15}/rail.py +0 -0
- /dodal/devices/{i18 → beamlines/i17}/__init__.py +0 -0
- /dodal/devices/{i19 → beamlines/i18}/__init__.py +0 -0
- /dodal/devices/{i18 → beamlines/i18}/kb_mirror.py +0 -0
- /dodal/devices/{i19/access_controlled → beamlines/i19}/__init__.py +0 -0
- /dodal/devices/{i20_1 → beamlines/i19/access_controlled}/__init__.py +0 -0
- /dodal/devices/{i19 → beamlines/i19}/access_controlled/hutch_access.py +0 -0
- /dodal/devices/{i19 → beamlines/i19}/beamstop.py +0 -0
- /dodal/devices/{i19 → beamlines/i19}/diffractometer.py +0 -0
- /dodal/devices/{i22 → beamlines/i20_1}/__init__.py +0 -0
- /dodal/devices/{i21 → beamlines/i21}/enums.py +0 -0
- /dodal/devices/{i24 → beamlines/i22}/__init__.py +0 -0
- /dodal/devices/{p99 → beamlines/i24}/__init__.py +0 -0
- /dodal/devices/{i24 → beamlines/i24}/aperture.py +0 -0
- /dodal/devices/{i24 → beamlines/i24}/focus_mirrors.py +0 -0
- /dodal/devices/{i24 → beamlines/i24}/vgonio.py +0 -0
- /dodal/devices/{p60 → beamlines/p60}/__init__.py +0 -0
- /dodal/devices/{p60 → beamlines/p60}/enums.py +0 -0
- /dodal/devices/{p99 → beamlines/p99}/sample_stage.py +0 -0
- /dodal/devices/insertion_device/{id_enum.py → enum.py} +0 -0
dodal/cli.py
CHANGED
|
@@ -24,6 +24,40 @@ def main(ctx: click.Context) -> None:
|
|
|
24
24
|
print("Please invoke subcommand!")
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
@main.command(name="describe")
|
|
28
|
+
@click.argument(
|
|
29
|
+
"beamline",
|
|
30
|
+
type=click.Choice(list(all_beamline_names())),
|
|
31
|
+
required=True,
|
|
32
|
+
)
|
|
33
|
+
@click.option("-n", "--name", "device_manager", default="devices")
|
|
34
|
+
def describe(beamline: str, device_manager: str) -> None:
|
|
35
|
+
"""Initialises a beamline module, gets the docs of all devices and prints them."""
|
|
36
|
+
os.environ["BEAMLINE"] = beamline
|
|
37
|
+
|
|
38
|
+
module_name = module_name_for_beamline(beamline)
|
|
39
|
+
full_module_path = f"dodal.beamlines.{module_name}"
|
|
40
|
+
|
|
41
|
+
print(f"Analysing {beamline} (using {full_module_path})")
|
|
42
|
+
|
|
43
|
+
mod = importlib.import_module(full_module_path)
|
|
44
|
+
|
|
45
|
+
if (manager := getattr(mod, device_manager, None)) and isinstance(
|
|
46
|
+
manager, DeviceManager
|
|
47
|
+
):
|
|
48
|
+
factories = manager.get_all_factories()
|
|
49
|
+
else:
|
|
50
|
+
print(
|
|
51
|
+
f"No device manager named '{device_manager}' found in {mod}, convert the beamline to use device manager"
|
|
52
|
+
)
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
for device_name, factory in sorted(factories.items()):
|
|
56
|
+
print(f"{device_name}:")
|
|
57
|
+
print(factory.__doc__)
|
|
58
|
+
print("*****************************************")
|
|
59
|
+
|
|
60
|
+
|
|
27
61
|
@main.command(name="connect")
|
|
28
62
|
@click.argument(
|
|
29
63
|
"beamline",
|
|
@@ -48,8 +82,8 @@ def main(ctx: click.Context) -> None:
|
|
|
48
82
|
@click.option("-n", "--name", "device_manager", default="devices")
|
|
49
83
|
def connect(beamline: str, all: bool, sim_backend: bool, device_manager: str) -> None:
|
|
50
84
|
"""Initialises a beamline module, connects to all devices, reports
|
|
51
|
-
any connection issues.
|
|
52
|
-
|
|
85
|
+
any connection issues.
|
|
86
|
+
"""
|
|
53
87
|
os.environ["BEAMLINE"] = beamline
|
|
54
88
|
|
|
55
89
|
# We need to make a fake path provider for any detectors that need one,
|
dodal/common/__init__.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from .coordination import group_uuid, inject
|
|
2
2
|
from .enums import EnabledDisabledUpper, InOutUpper, OnOffUpper
|
|
3
|
-
from .maths import in_micros, step_to_num
|
|
3
|
+
from .maths import Rectangle2D, in_micros, step_to_num
|
|
4
4
|
from .types import MsgGenerator, PlanGenerator
|
|
5
5
|
|
|
6
6
|
__all__ = [
|
|
@@ -13,4 +13,5 @@ __all__ = [
|
|
|
13
13
|
"MsgGenerator",
|
|
14
14
|
"PlanGenerator",
|
|
15
15
|
"step_to_num",
|
|
16
|
+
"Rectangle2D",
|
|
16
17
|
]
|
|
@@ -63,7 +63,8 @@ class GDABeamlineParameters:
|
|
|
63
63
|
|
|
64
64
|
def get_beamline_parameters(beamline_param_path: str | None = None):
|
|
65
65
|
"""Loads the beamline parameters from the specified path, or according to the
|
|
66
|
-
environment variable if none is given
|
|
66
|
+
environment variable if none is given.
|
|
67
|
+
"""
|
|
67
68
|
if not beamline_param_path:
|
|
68
69
|
beamline_name = get_beamline_name("i03")
|
|
69
70
|
beamline_param_path = BEAMLINE_PARAMETER_PATHS.get(beamline_name)
|
|
@@ -93,15 +93,17 @@ def device_instantiation(
|
|
|
93
93
|
define lists of devices in beamline files. Additional keyword arguments are passed
|
|
94
94
|
directly to the device constructor.
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
device_factory
|
|
98
|
-
name
|
|
99
|
-
prefix
|
|
100
|
-
wait
|
|
101
|
-
fake
|
|
102
|
-
post_create:
|
|
103
|
-
|
|
104
|
-
bl_prefix
|
|
96
|
+
Args:
|
|
97
|
+
device_factory (Callable): The device class.
|
|
98
|
+
name (str): The name for ophyd.
|
|
99
|
+
prefix (str): The PV prefix for the most (usually all) components.
|
|
100
|
+
wait (bool): Whether to run .wait_for_connection().
|
|
101
|
+
fake (bool): Whether to fake with ophyd.sim.
|
|
102
|
+
post_create (Callable): (optional) a function to be run on the device after
|
|
103
|
+
creation.
|
|
104
|
+
bl_prefix (bool): If true, add the beamline prefix when instantiating.
|
|
105
|
+
**kwargs: Arguments passed on to every device factory.
|
|
106
|
+
|
|
105
107
|
Returns:
|
|
106
108
|
The instance of the device.
|
|
107
109
|
"""
|
|
@@ -15,7 +15,8 @@ _commissioning_signal: SignalR | None = None
|
|
|
15
15
|
def read_commissioning_mode() -> MsgGenerator[bool]:
|
|
16
16
|
"""Utility method for reading the commissioning mode state from the context
|
|
17
17
|
of a bluesky plan, where a baton may or may not be present, or
|
|
18
|
-
commissioning mode is provided by some other mechanism.
|
|
18
|
+
commissioning mode is provided by some other mechanism.
|
|
19
|
+
"""
|
|
19
20
|
if _commissioning_signal:
|
|
20
21
|
return (yield from bps.rd(_commissioning_signal))
|
|
21
22
|
else:
|
|
@@ -26,8 +27,10 @@ def set_commissioning_signal(signal: SignalR[bool] | None):
|
|
|
26
27
|
"""Commissioning mode is enabled by a PV which when set enables commissioning mode.
|
|
27
28
|
This allows beamline staff to ensure that commissioning mode is disabled prior
|
|
28
29
|
to production use, via their own 'good morning' startup scripts.
|
|
30
|
+
|
|
29
31
|
Args:
|
|
30
|
-
signal: The signal which will be read in order to determine whether
|
|
31
|
-
|
|
32
|
+
signal (SignalR): The signal which will be read in order to determine whether
|
|
33
|
+
commissioning mode is enabled.
|
|
34
|
+
"""
|
|
32
35
|
global _commissioning_signal
|
|
33
36
|
_commissioning_signal = signal
|
dodal/common/coordination.py
CHANGED
|
@@ -5,37 +5,35 @@ from dodal.common.types import Group
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
def group_uuid(name: str) -> Group:
|
|
8
|
-
"""
|
|
9
|
-
|
|
8
|
+
"""Returns a unique but human-readable string, to assist debugging orchestrated
|
|
9
|
+
groups.
|
|
10
10
|
|
|
11
11
|
Args:
|
|
12
|
-
name (str): A human readable name
|
|
12
|
+
name (str): A human readable name.
|
|
13
13
|
|
|
14
14
|
Returns:
|
|
15
|
-
readable_uid (Group):
|
|
15
|
+
readable_uid (Group): Name appended with a unique string.
|
|
16
16
|
"""
|
|
17
17
|
return f"{name}-{str(uuid.uuid4())[:6]}"
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def inject(name: str = "") -> Any: # type: ignore
|
|
21
|
-
"""
|
|
22
|
-
Function to mark a defaulted argument of a plan as a reference to a device stored
|
|
21
|
+
"""Function to mark a defaulted argument of a plan as a reference to a device stored
|
|
23
22
|
in another context and not available to be referenced directly.
|
|
23
|
+
|
|
24
24
|
Bypasses type checking, returning x as Any and therefore valid as a default
|
|
25
|
-
argument, leaving handling to the context from which the plan is called.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
name "stage_x"
|
|
25
|
+
argument, leaving handling to the context from which the plan is called. Assumes
|
|
26
|
+
that device.name is unique. e.g. For a 1-dimensional scan, that is usually performed
|
|
27
|
+
on a Movable with name "stage_x"::
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
def scan(x: Movable = inject("stage_x"), start: float = 0.0 ...)
|
|
31
30
|
|
|
32
31
|
Args:
|
|
33
32
|
name (str): Name of a Device to be fetched from an external context. This can be
|
|
34
|
-
|
|
33
|
+
left blank when injecting device composites (the default).
|
|
35
34
|
|
|
36
35
|
Returns:
|
|
37
|
-
Any:
|
|
36
|
+
Any: Name but without typing checking, valid as any default type.
|
|
38
37
|
|
|
39
38
|
"""
|
|
40
|
-
|
|
41
39
|
return name
|
dodal/common/crystal_metadata.py
CHANGED
|
@@ -6,9 +6,7 @@ from typing import Literal
|
|
|
6
6
|
|
|
7
7
|
@dataclass(frozen=True)
|
|
8
8
|
class Material:
|
|
9
|
-
"""
|
|
10
|
-
Class representing a crystalline material with a specific lattice parameter.
|
|
11
|
-
"""
|
|
9
|
+
"""Class representing a crystalline material with a specific lattice parameter."""
|
|
12
10
|
|
|
13
11
|
name: str
|
|
14
12
|
lattice_parameter: float # Lattice parameter in meters
|
|
@@ -21,9 +19,8 @@ class MaterialsEnum(Enum):
|
|
|
21
19
|
|
|
22
20
|
@dataclass(frozen=True)
|
|
23
21
|
class CrystalMetadata:
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
see https://manual.nexusformat.org/classes/base_classes/NXcrystal.html
|
|
22
|
+
"""Metadata used in the NeXus format,
|
|
23
|
+
see https://manual.nexusformat.org/classes/base_classes/NXcrystal.html.
|
|
27
24
|
"""
|
|
28
25
|
|
|
29
26
|
usage: Literal["Bragg", "Laue"]
|
|
@@ -35,8 +32,8 @@ class CrystalMetadata:
|
|
|
35
32
|
def calculate_default_d_spacing(
|
|
36
33
|
lattice_parameter: float, reflection: tuple[int, int, int]
|
|
37
34
|
) -> tuple[float, str]:
|
|
38
|
-
"""
|
|
39
|
-
|
|
35
|
+
"""Calculates the d-spacing value in nanometers based on the given lattice
|
|
36
|
+
parameter and reflection indices.
|
|
40
37
|
"""
|
|
41
38
|
h_index, k_index, l_index = reflection
|
|
42
39
|
d_spacing_m = lattice_parameter / math.sqrt(
|
dodal/common/device_utils.py
CHANGED
|
@@ -19,11 +19,12 @@ async def periodic_reminder(
|
|
|
19
19
|
"""Periodically logs a message according to a schedule with increasing delays.
|
|
20
20
|
|
|
21
21
|
Args:
|
|
22
|
-
message: The message the user wants to output through logging.
|
|
23
|
-
schedule: A tuple list of tuples consisting of (int|float, int|None).
|
|
22
|
+
message (str): The message the user wants to output through logging.
|
|
23
|
+
schedule (tuple): A tuple list of tuples consisting of (int|float, int|None).
|
|
24
24
|
A sequence of (delay_seconds, count) pairs defining the logging intervals.
|
|
25
25
|
- delay_seconds is the number of seconds to wait between logs.
|
|
26
|
-
- count is how many times to log at this interval. If count is None, it logs
|
|
26
|
+
- count is how many times to log at this interval. If count is None, it logs
|
|
27
|
+
indefinitely at that delay.
|
|
27
28
|
"""
|
|
28
29
|
|
|
29
30
|
async def _log_loop():
|
dodal/common/maths.py
CHANGED
|
@@ -2,28 +2,24 @@ import numpy as np
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
def step_to_num(start: float, stop: float, step: float) -> tuple[float, float, int]:
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
Forces step to be same direction as length
|
|
5
|
+
"""Standard handling for converting from start, stop, step to start, stop, num.
|
|
6
|
+
Forces step to be same direction as length.
|
|
8
7
|
Includes a final point if it is within 1% of the final step, prevents floating
|
|
9
8
|
point arithmatic errors from giving inconsistent shaped scans between steps of an
|
|
10
9
|
outer axis.
|
|
11
10
|
|
|
12
11
|
Args:
|
|
13
|
-
start (float):
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
step (float):
|
|
19
|
-
Length of a step along the line formed from start to stop.
|
|
20
|
-
If stop < start, will be coerced to be backwards.
|
|
12
|
+
start (float): Start of length, will be returned unchanged.
|
|
13
|
+
stop (float): End of length, if length/step does not divide cleanly will be
|
|
14
|
+
returned extended up to 1% of step, or else truncated.
|
|
15
|
+
step (float): Length of a step along the line formed from start to stop. If
|
|
16
|
+
stop < start, will be coerced to be backwards.
|
|
21
17
|
|
|
22
18
|
Returns:
|
|
23
19
|
start, adjusted_stop, num = Tuple[float, float, int]
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
- start will be returned unchanged.
|
|
21
|
+
- adjusted_stop = start + (num - 1) * step.
|
|
22
|
+
- num is the maximal number of steps that could fit into the length.
|
|
27
23
|
|
|
28
24
|
"""
|
|
29
25
|
# Make step be the right direction
|
|
@@ -34,17 +30,89 @@ def step_to_num(start: float, stop: float, step: float) -> tuple[float, float, i
|
|
|
34
30
|
|
|
35
31
|
|
|
36
32
|
def in_micros(t: float) -> int:
|
|
37
|
-
"""
|
|
38
|
-
Converts between a positive number of seconds and an equivalent
|
|
33
|
+
"""Converts between a positive number of seconds and an equivalent
|
|
39
34
|
number of microseconds.
|
|
40
35
|
|
|
41
36
|
Args:
|
|
42
|
-
t (float): A time in seconds
|
|
37
|
+
t (float): A time in seconds.
|
|
38
|
+
|
|
43
39
|
Raises:
|
|
44
|
-
ValueError: if t < 0
|
|
40
|
+
ValueError: if t < 0.
|
|
41
|
+
|
|
45
42
|
Returns:
|
|
46
|
-
|
|
43
|
+
int: A time in microseconds, rounded up to the nearest whole microsecond.
|
|
47
44
|
"""
|
|
48
45
|
if t < 0:
|
|
49
46
|
raise ValueError(f"Expected a positive time in seconds, got {t!r}")
|
|
50
47
|
return int(np.ceil(t * 1e6))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class Rectangle2D:
|
|
51
|
+
"""A 2D rectangle defined by two opposite corners.
|
|
52
|
+
|
|
53
|
+
This class represents a rectangle in 2D space using two points: (x1, y1) and (x2, y2).
|
|
54
|
+
It provides methods to query rectangle properties and check point containment.
|
|
55
|
+
|
|
56
|
+
Attributes:
|
|
57
|
+
x1 (float): The x-coordinate of the first corner.
|
|
58
|
+
y1 (float): The y-coordinate of the first corner.
|
|
59
|
+
x2 (float): The x-coordinate of the second corner.
|
|
60
|
+
y2 (float): The y-coordinate of the second corner.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
x1 (float): The x-coordinate of the first corner.
|
|
64
|
+
y1 (float): The y-coordinate of the first corner.
|
|
65
|
+
x2 (float): The x-coordinate of the second corner.
|
|
66
|
+
y2 (float): The y-coordinate of the second corner.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
def __init__(self, x1: float, y1: float, x2: float, y2: float):
|
|
70
|
+
self.x1, self.y1 = x1, y1
|
|
71
|
+
self.x2, self.y2 = x2, y2
|
|
72
|
+
|
|
73
|
+
def get_max_x(self) -> float:
|
|
74
|
+
"""Get the maximum x-coordinate of the rectangle.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
float: The larger of the two x-coordinates (x1, x2).
|
|
78
|
+
"""
|
|
79
|
+
return max(self.x1, self.x2)
|
|
80
|
+
|
|
81
|
+
def get_min_x(self) -> float:
|
|
82
|
+
"""Get the minimum x-coordinate of the rectangle.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
float: The smaller of the two x-coordinates (x1, x2).
|
|
86
|
+
"""
|
|
87
|
+
return min(self.x1, self.x2)
|
|
88
|
+
|
|
89
|
+
def get_max_y(self) -> float:
|
|
90
|
+
"""Get the maximum y-coordinate of the rectangle.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
float: The larger of the two y-coordinates (y1, y2).
|
|
94
|
+
"""
|
|
95
|
+
return max(self.y1, self.y2)
|
|
96
|
+
|
|
97
|
+
def get_min_y(self) -> float:
|
|
98
|
+
"""Get the minimum y-coordinate of the rectangle.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
float: The smaller of the two y-coordinates (y1, y2).
|
|
102
|
+
"""
|
|
103
|
+
return min(self.y1, self.y2)
|
|
104
|
+
|
|
105
|
+
def contains(self, x: float, y: float) -> bool:
|
|
106
|
+
"""Check if a point is contained within the rectangle.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
x (float): The x-coordinate of the point.
|
|
110
|
+
y (float): The y-coordinate of the point.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
bool: True if the point is within the rectangle bounds, False otherwise.
|
|
114
|
+
"""
|
|
115
|
+
return (
|
|
116
|
+
self.get_min_x() <= x <= self.get_max_x()
|
|
117
|
+
and self.get_min_y() <= y <= self.get_max_y()
|
|
118
|
+
)
|
|
@@ -16,7 +16,8 @@ class PandAFilenameProvider(FilenameProvider):
|
|
|
16
16
|
|
|
17
17
|
class PandASubpathProvider(UpdatingPathProvider):
|
|
18
18
|
"""Directory provider for the HDFPanda. Points to a panda subdirectory within the
|
|
19
|
-
directory path provided
|
|
19
|
+
directory path provided.
|
|
20
|
+
"""
|
|
20
21
|
|
|
21
22
|
resource_dir = Path("panda")
|
|
22
23
|
|
|
@@ -34,13 +35,17 @@ class PandASubpathProvider(UpdatingPathProvider):
|
|
|
34
35
|
return self._filename_provider.suffix or ""
|
|
35
36
|
|
|
36
37
|
async def update(self, *, directory: Path, suffix: str = "", **kwargs):
|
|
37
|
-
"""Update the root directory into which panda pcap files are written. This will
|
|
38
|
-
subdirectory being created if it does not already exist.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
"""Update the root directory into which panda pcap files are written. This will
|
|
39
|
+
result in the panda subdirectory being created if it does not already exist.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
directory (Path): Instance that identifies the root folder. This folder must
|
|
43
|
+
exist. The panda will attempt to write into the "panda" subdirectory
|
|
44
|
+
which will be created if not already present.
|
|
45
|
+
suffix (str, optional): Optional str that will be appended to the panda
|
|
46
|
+
device name along with the file type extension to construct the output
|
|
47
|
+
filename.
|
|
48
|
+
**kwargs: Seemingly unused.
|
|
44
49
|
"""
|
|
45
50
|
self._output_directory = directory / self.resource_dir
|
|
46
51
|
self._filename_provider.suffix = suffix
|
dodal/common/visit.py
CHANGED
|
@@ -9,32 +9,29 @@ from pydantic import BaseModel, Field
|
|
|
9
9
|
from dodal.common.types import UpdatingPathProvider
|
|
10
10
|
from dodal.log import LOGGER
|
|
11
11
|
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
"""
|
|
12
|
+
"""Functionality required for/from the API of a DirectoryService which exposes the
|
|
13
|
+
specifics of the Diamond filesystem."""
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
class DataCollectionIdentifier(BaseModel):
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
"""Equivalent to a `Scan Number` or `scan_id`, non-globally unique scan identifier.
|
|
18
|
+
Should be always incrementing, unique per-visit, co-ordinated with any other scan
|
|
19
|
+
engines.
|
|
21
20
|
"""
|
|
22
21
|
|
|
23
22
|
collection_number: int = Field(alias="collectionNumber")
|
|
24
23
|
|
|
25
24
|
|
|
26
25
|
class DirectoryServiceClient(ABC):
|
|
27
|
-
"""
|
|
28
|
-
Object responsible for I/O in determining collection number
|
|
29
|
-
"""
|
|
26
|
+
"""Object responsible for I/O in determining collection number."""
|
|
30
27
|
|
|
31
28
|
@abstractmethod
|
|
32
29
|
async def create_new_collection(self) -> DataCollectionIdentifier:
|
|
33
|
-
"""Create new collection"""
|
|
30
|
+
"""Create new collection."""
|
|
34
31
|
|
|
35
32
|
@abstractmethod
|
|
36
33
|
async def get_current_collection(self) -> DataCollectionIdentifier:
|
|
37
|
-
"""Get current collection"""
|
|
34
|
+
"""Get current collection."""
|
|
38
35
|
|
|
39
36
|
|
|
40
37
|
class DiamondFilenameProvider(FilenameProvider):
|
|
@@ -50,9 +47,9 @@ class DiamondFilenameProvider(FilenameProvider):
|
|
|
50
47
|
|
|
51
48
|
|
|
52
49
|
class RemoteDirectoryServiceClient(DirectoryServiceClient):
|
|
53
|
-
"""Client for the VisitService REST API
|
|
50
|
+
"""Client for the VisitService REST API.
|
|
54
51
|
Currently exposed by the GDA Server to co-ordinate unique filenames.
|
|
55
|
-
While VisitService is embedded in GDA, url is likely to be `ixx-control:8088/api
|
|
52
|
+
While VisitService is embedded in GDA, url is likely to be `ixx-control:8088/api`.
|
|
56
53
|
"""
|
|
57
54
|
|
|
58
55
|
def __init__(self, url: str) -> None:
|
|
@@ -98,13 +95,15 @@ class LocalDirectoryServiceClient(DirectoryServiceClient):
|
|
|
98
95
|
|
|
99
96
|
|
|
100
97
|
class StaticVisitPathProvider(UpdatingPathProvider):
|
|
101
|
-
"""
|
|
102
|
-
|
|
98
|
+
"""Static (single visit) implementation of PathProvider whilst awaiting auth
|
|
99
|
+
infrastructure to generate necessary information per-scan.
|
|
103
100
|
Allows setting a singular visit into which all run files will be saved.
|
|
104
|
-
update() queries a visit service to get the next DataCollectionIdentifier to
|
|
101
|
+
update() queries a visit service to get the next DataCollectionIdentifier to
|
|
102
|
+
increment the suffix of all file writers' next files.
|
|
105
103
|
Requires that all detectors are running with a mutual view on the filesystem.
|
|
106
|
-
Supports a single Visit which should be passed as a Path relative to the root of
|
|
107
|
-
|
|
104
|
+
Supports a single Visit which should be passed as a Path relative to the root of
|
|
105
|
+
the Detector IOC mounting.
|
|
106
|
+
i.e. to write to visit `/dls/ixx/data/YYYY/cm12345-1`.
|
|
108
107
|
"""
|
|
109
108
|
|
|
110
109
|
def __init__(
|
|
@@ -123,9 +122,7 @@ class StaticVisitPathProvider(UpdatingPathProvider):
|
|
|
123
122
|
self._session: ClientSession | None
|
|
124
123
|
|
|
125
124
|
async def update(self, **kwargs) -> None:
|
|
126
|
-
"""
|
|
127
|
-
Creates a new data collection in the current visit.
|
|
128
|
-
"""
|
|
125
|
+
"""Creates a new data collection in the current visit."""
|
|
129
126
|
# https://github.com/DiamondLightSource/dodal/issues/452
|
|
130
127
|
# TODO: Allow selecting visit as part of a request
|
|
131
128
|
# TODO: DAQ-4827: Pass AuthN information as part of request
|
dodal/common/watcher_utils.py
CHANGED
|
@@ -55,22 +55,24 @@ def log_on_percentage_complete(
|
|
|
55
55
|
message_prefix: str,
|
|
56
56
|
percent_interval: int = 25,
|
|
57
57
|
):
|
|
58
|
-
"""
|
|
59
|
-
|
|
58
|
+
"""Add watcher to a WatchableAsyncStatus status which will periodically log a
|
|
59
|
+
message based on percentage completion.
|
|
60
60
|
|
|
61
61
|
Args:
|
|
62
|
-
status
|
|
63
|
-
|
|
64
|
-
message_prefix: The string at the start of each of the produced logging
|
|
65
|
-
|
|
66
|
-
percent_interval: How often to produce logging message, in
|
|
67
|
-
|
|
62
|
+
status (WatchableAsyncStatus): For example, Ophyd-async produces this status
|
|
63
|
+
from a Motor.set method.
|
|
64
|
+
message_prefix (str): The string at the start of each of the produced logging
|
|
65
|
+
messages
|
|
66
|
+
percent_interval (int, optional): How often to produce logging message, in
|
|
67
|
+
terms of percentage completion of the status.
|
|
68
68
|
|
|
69
69
|
Note that when using with Bluesky plan stubs you will need to cast the status (as of
|
|
70
|
-
Bluesky v1.14.2), since a Bluesky status doesn't use generics - see
|
|
70
|
+
Bluesky v1.14.2), since a Bluesky status doesn't use generics - see
|
|
71
|
+
https://github.com/bluesky/bluesky/issues/1948.
|
|
71
72
|
|
|
72
|
-
When running Bluesky plans using an interactive terminal, it is better to use the
|
|
73
|
-
bar instead of this function. See
|
|
73
|
+
When running Bluesky plans using an interactive terminal, it is better to use the
|
|
74
|
+
standard bluesky progress bar instead of this function. See
|
|
75
|
+
https://blueskyproject.io/bluesky/main/progress-bar.html#progress-bar.
|
|
74
76
|
|
|
75
77
|
Example usage within a Bluesky plan:
|
|
76
78
|
yield from bps.kickoff(my_detector)
|
|
@@ -78,6 +80,5 @@ def log_on_percentage_complete(
|
|
|
78
80
|
status = cast(WatchableAsyncStatus, status)
|
|
79
81
|
log_on_percentage_complete(status, "Data collection triggers received", 10)
|
|
80
82
|
yield from bps.wait("collection complete")
|
|
81
|
-
|
|
82
83
|
"""
|
|
83
84
|
_LogOnPercentageProgressWatcher(status, message_prefix, percent_interval)
|