From 989e579ca529086a48fe34030c4e9bca5747b9d1 Mon Sep 17 00:00:00 2001 From: Jacob Williamson Date: Tue, 9 Dec 2025 09:05:36 +0000 Subject: [PATCH 1/6] Use config server to read pitch and roll config --- .../dcm_pitch_roll_mirror_adjuster.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py b/src/mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py index 60a1188e82..e682948521 100644 --- a/src/mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +++ b/src/mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py @@ -1,6 +1,8 @@ import json import bluesky.plan_stubs as bps +from daq_config_server.client import ConfigServer +from daq_config_server.converters.models import GenericLookupTable from dodal.devices.focusing_mirror import ( FocusingMirrorWithStripes, MirrorStripe, @@ -10,7 +12,6 @@ from dodal.devices.util.adjuster_plans import lookup_table_adjuster from dodal.devices.util.lookup_tables import ( linear_interpolation_lut, - parse_lookup_table, ) from mx_bluesky.common.utils.log import LOGGER @@ -114,12 +115,15 @@ def adjust_dcm_pitch_roll_vfm_from_lut( d_spacing_a: float = yield from bps.rd( undulator_dcm.dcm_ref().crystal_metadata_d_spacing_a ) + config_server = ConfigServer(url="https://daq-config.diamond.ac.uk") + pitch_energy_table = config_server.get_file_contents( + undulator_dcm.pitch_energy_table_path, GenericLookupTable + ) + bragg_deg = energy_to_bragg_angle(energy_kev, d_spacing_a) LOGGER.info(f"Target Bragg angle = {bragg_deg} degrees") dcm_pitch_adjuster = lookup_table_adjuster( - linear_interpolation_lut( - *parse_lookup_table(undulator_dcm.pitch_energy_table_path) - ), + linear_interpolation_lut(*pitch_energy_table.columns()), dcm.xtal_1.pitch_in_mrad, bragg_deg, ) @@ -128,10 +132,11 @@ def adjust_dcm_pitch_roll_vfm_from_lut( LOGGER.info("Waiting for DCM pitch adjust to complete...") # DCM Roll + roll_energy_table = config_server.get_file_contents( + undulator_dcm.roll_energy_table_path, GenericLookupTable + ) dcm_roll_adjuster = lookup_table_adjuster( - linear_interpolation_lut( - *parse_lookup_table(undulator_dcm.roll_energy_table_path) - ), + linear_interpolation_lut(*roll_energy_table.columns()), dcm.xtal_1.roll_in_mrad, bragg_deg, ) From 85474528c14cd69517f54500fd71230b89a4e64a Mon Sep 17 00:00:00 2001 From: Jacob Williamson Date: Tue, 9 Dec 2025 09:06:07 +0000 Subject: [PATCH 2/6] Fix tests and test data --- tests/conftest.py | 31 ++++- .../BeamLineEnergy_DCM_Pitch_converter.txt | 49 ++++---- .../BeamLineEnergy_DCM_Roll_converter.txt | 13 +- .../lookup/BeamLine_Undulator_toGap.txt | 115 +++++++++--------- 4 files changed, 116 insertions(+), 92 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 66eea68538..0814eea180 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -77,6 +77,7 @@ from ophyd_async.epics.motor import Motor from ophyd_async.fastcs.panda import DatasetTable, PandaHdf5DatasetType from PIL import Image +from pydantic import BaseModel from pydantic.dataclasses import dataclass from scanspec.core import Path as ScanPath from scanspec.specs import Line @@ -1723,7 +1724,7 @@ def _fake_config_server_read( @pytest.fixture(autouse=True) -def mock_config_server(): +def mock_mx_config_server(): # Don't actually talk to central service during unit tests, and reset caches between test for client in IMPLEMENTED_CONFIG_CLIENTS: @@ -1736,6 +1737,34 @@ def mock_config_server(): yield +def _fake_config_server_get_file_contents( + filepath: str | Path, + desired_return_type: type[str] | type[dict] | BaseModel = str, + reset_cached_result=False, +): + filepath = Path(filepath) + # Minimal logic required for unit tests + with filepath.open("r") as f: + contents = f.read() + if desired_return_type is str: + return contents + elif desired_return_type is dict: + return json.loads(contents) + elif issubclass(desired_return_type, BaseModel): # type: ignore + return desired_return_type.model_validate(json.loads(contents)) + + +@pytest.fixture(autouse=True) +def mock_config_server(): + # Don't actually talk to central service during unit tests, and reset caches between test + + with patch( + "daq_config_server.client.ConfigServer.get_file_contents", + side_effect=_fake_config_server_get_file_contents, + ): + yield + + def mock_beamline_module_filepaths(bl_name, bl_module): if mock_attributes := mock_attributes_table.get(bl_name): [bl_module.__setattr__(attr[0], attr[1]) for attr in mock_attributes] diff --git a/tests/test_data/test_daq_configuration/lookup/BeamLineEnergy_DCM_Pitch_converter.txt b/tests/test_data/test_daq_configuration/lookup/BeamLineEnergy_DCM_Pitch_converter.txt index 449e920f73..4552873392 100644 --- a/tests/test_data/test_daq_configuration/lookup/BeamLineEnergy_DCM_Pitch_converter.txt +++ b/tests/test_data/test_daq_configuration/lookup/BeamLineEnergy_DCM_Pitch_converter.txt @@ -1,25 +1,24 @@ -# Bragg pitch -# Degree values for pitch are interpreted as mrad -# The values cannot change direction. -# last update 2023/06/26 NP -Units Deg mrad -Units Deg Deg -19.24347 -0.79775 -16.40949 -0.78679 -14.31123 -0.77838 -12.69287 -0.77276 -11.40555 -0.77276 -10.35662 -0.77031 -9.48522 -0.76693 -8.95826 -0.76387 -8.74953 -0.76387 -8.12020 -0.76387 -7.57556 -0.76354 -7.09950 -0.76166 -6.67997 -0.76044 -6.30732 -0.75953 -5.97411 -0.75845 -5.67434 -0.75796 -5.40329 -0.75789 -5.15700 -0.75551 -4.93218 -0.75513 +{ + "column_names": ["bragg_angle_deg", "pitch_mrad"], + "rows": [ + [19.24347, -0.79775], + [16.40949, -0.78679], + [14.31123, -0.77838], + [12.69287, -0.77276], + [11.40555, -0.77276], + [10.35662, -0.77031], + [9.48522, -0.76693], + [8.95826, -0.76387], + [8.74953, -0.76387], + [8.1202, -0.76387], + [7.57556, -0.76354], + [7.0995, -0.76166], + [6.67997, -0.76044], + [6.30732, -0.75953], + [5.97411, -0.75845], + [5.67434, -0.75796], + [5.40329, -0.75789], + [5.157, -0.75551], + [4.93218, -0.75513] + ] +} diff --git a/tests/test_data/test_daq_configuration/lookup/BeamLineEnergy_DCM_Roll_converter.txt b/tests/test_data/test_daq_configuration/lookup/BeamLineEnergy_DCM_Roll_converter.txt index 9b5b52dcb7..f11e833493 100644 --- a/tests/test_data/test_daq_configuration/lookup/BeamLineEnergy_DCM_Roll_converter.txt +++ b/tests/test_data/test_daq_configuration/lookup/BeamLineEnergy_DCM_Roll_converter.txt @@ -1,6 +1,7 @@ -#Bragg angle against roll( absolute number) -#reloadLookupTables() -# last update 2023/01/19 NP -Units Deg mrad -26.4095 -0.2799 -6.3075 -0.2799 +{ + "column_names": ["bragg_angle_deg", "roll_mrad"], + "rows": [ + [26.4095, -0.2799], + [6.3075, -0.2799] + ] +} diff --git a/tests/test_data/test_daq_configuration/lookup/BeamLine_Undulator_toGap.txt b/tests/test_data/test_daq_configuration/lookup/BeamLine_Undulator_toGap.txt index 4dfe25c74e..61575edf1b 100755 --- a/tests/test_data/test_daq_configuration/lookup/BeamLine_Undulator_toGap.txt +++ b/tests/test_data/test_daq_configuration/lookup/BeamLine_Undulator_toGap.txt @@ -1,60 +1,55 @@ -####################### -# # -# 5.5mm CPMU 20/11/22 # -# # -####################### -# Used to convert from energy to gap. Constructed from tables for 3rd, 5th and 7th harmonic. -# It is important that at the point of change from one harmonic to another that there is -# point for the same energy from both harmomics to prevent invalid interpolation. -# run reloadLookupTables() when done -Units eV mm -5700 5.4606 -5760 5.5 -6000 5.681 -6500 6.045 -7000 6.404 -7500 6.765 -8000 7.124 -8500 7.491 -9000 7.872 -9500 8.258 -9700 8.424 -9700 5.542 -10000 5.675 -10500 5.895 -11000 6.113 -11500 6.328 -12000 6.545 -12500 6.758 -12700 6.83 -13000 6.98 -13443 7.168 -13443 5.5 -13500 5.517 -14000 5.674 -14500 5.831 -15000 5.987 -15500 6.139 -16000 6.294 -16500 6.447 -17000 6.603 -17320 6.697 -17320 5.5 -17500 5.552 -18000 5.674 -18500 5.794 -19000 5.912 -19500 6.037 -20000 6.157 -20500 6.277 -20939 6.378 -20939 5.5 -21000 5.517 -21500 5.577 -22000 5.674 -22500 5.773 -23000 5.871 -23500 5.97 -24000 6.072 -24500 6.167 -25000 6.264 +{ + "column_names": ["energy_eV", "gap_mm"], + "rows": [ + [5700, 5.4606], + [5760, 5.5], + [6000, 5.681], + [6500, 6.045], + [7000, 6.404], + [7500, 6.765], + [8000, 7.124], + [8500, 7.491], + [9000, 7.872], + [9500, 8.258], + [9700, 8.424], + [9700, 5.542], + [10000, 5.675], + [10500, 5.895], + [11000, 6.113], + [11500, 6.328], + [12000, 6.545], + [12500, 6.758], + [12700, 6.83], + [13000, 6.98], + [13443, 7.168], + [13443, 5.5], + [13500, 5.517], + [14000, 5.674], + [14500, 5.831], + [15000, 5.987], + [15500, 6.139], + [16000, 6.294], + [16500, 6.447], + [17000, 6.603], + [17320, 6.697], + [17320, 5.5], + [17500, 5.552], + [18000, 5.674], + [18500, 5.794], + [19000, 5.912], + [19500, 6.037], + [20000, 6.157], + [20500, 6.277], + [20939, 6.378], + [20939, 5.5], + [21000, 5.517], + [21500, 5.577], + [22000, 5.674], + [22500, 5.773], + [23000, 5.871], + [23500, 5.97], + [24000, 6.072], + [24500, 6.167], + [25000, 6.264] + ] +} From 0ec62f4124b8fbd40f353d482d44b118ac41e465 Mon Sep 17 00:00:00 2001 From: Jacob Williamson Date: Tue, 9 Dec 2025 09:07:01 +0000 Subject: [PATCH 3/6] Pin dodal and daq-config-server --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f22c5df38b..4f7c7fb70b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,12 +43,12 @@ dependencies = [ # These dependencies may be issued as pre-release versions and should have a pin constraint # as by default pip-install will not upgrade to a pre-release. # - "daq-config-server>=v1.0.0-rc.2", + "daq-config-server @ git+https://github.com/DiamondLightSource/daq-config-server.git@extend_lookup_table_model", "blueapi >= 1.8.0", "ophyd >= 1.10.5", "ophyd-async >= 0.14.0", "bluesky >= 1.14.6", - "dls-dodal @ git+https://github.com/DiamondLightSource/dodal.git@main", + "dls-dodal @ git+https://github.com/DiamondLightSource/dodal.git@mx_bluesky_1494_use_config_server_for_undulator", ] From 258737f3d551599545689bb9b5dc81c518607a7c Mon Sep 17 00:00:00 2001 From: Jacob Williamson Date: Tue, 6 Jan 2026 13:28:50 +0000 Subject: [PATCH 4/6] Use specific lut models for each undulator lut --- .../device_setup_plans/dcm_pitch_roll_mirror_adjuster.py | 6 +++--- .../lookup/BeamLineEnergy_DCM_Pitch_converter.txt | 1 - .../lookup/BeamLineEnergy_DCM_Roll_converter.txt | 1 - .../lookup/BeamLine_Undulator_toGap.txt | 1 - 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py b/src/mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py index e682948521..72da533e25 100644 --- a/src/mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +++ b/src/mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py @@ -2,7 +2,7 @@ import bluesky.plan_stubs as bps from daq_config_server.client import ConfigServer -from daq_config_server.converters.models import GenericLookupTable +from daq_config_server.models import BeamlinePitchLookupTable, BeamlineRollLookupTable from dodal.devices.focusing_mirror import ( FocusingMirrorWithStripes, MirrorStripe, @@ -117,7 +117,7 @@ def adjust_dcm_pitch_roll_vfm_from_lut( ) config_server = ConfigServer(url="https://daq-config.diamond.ac.uk") pitch_energy_table = config_server.get_file_contents( - undulator_dcm.pitch_energy_table_path, GenericLookupTable + undulator_dcm.pitch_energy_table_path, BeamlinePitchLookupTable ) bragg_deg = energy_to_bragg_angle(energy_kev, d_spacing_a) @@ -133,7 +133,7 @@ def adjust_dcm_pitch_roll_vfm_from_lut( # DCM Roll roll_energy_table = config_server.get_file_contents( - undulator_dcm.roll_energy_table_path, GenericLookupTable + undulator_dcm.roll_energy_table_path, BeamlineRollLookupTable ) dcm_roll_adjuster = lookup_table_adjuster( linear_interpolation_lut(*roll_energy_table.columns()), diff --git a/tests/test_data/test_daq_configuration/lookup/BeamLineEnergy_DCM_Pitch_converter.txt b/tests/test_data/test_daq_configuration/lookup/BeamLineEnergy_DCM_Pitch_converter.txt index 4552873392..54d32ddbe2 100644 --- a/tests/test_data/test_daq_configuration/lookup/BeamLineEnergy_DCM_Pitch_converter.txt +++ b/tests/test_data/test_daq_configuration/lookup/BeamLineEnergy_DCM_Pitch_converter.txt @@ -1,5 +1,4 @@ { - "column_names": ["bragg_angle_deg", "pitch_mrad"], "rows": [ [19.24347, -0.79775], [16.40949, -0.78679], diff --git a/tests/test_data/test_daq_configuration/lookup/BeamLineEnergy_DCM_Roll_converter.txt b/tests/test_data/test_daq_configuration/lookup/BeamLineEnergy_DCM_Roll_converter.txt index f11e833493..7f2a6fc2f9 100644 --- a/tests/test_data/test_daq_configuration/lookup/BeamLineEnergy_DCM_Roll_converter.txt +++ b/tests/test_data/test_daq_configuration/lookup/BeamLineEnergy_DCM_Roll_converter.txt @@ -1,5 +1,4 @@ { - "column_names": ["bragg_angle_deg", "roll_mrad"], "rows": [ [26.4095, -0.2799], [6.3075, -0.2799] diff --git a/tests/test_data/test_daq_configuration/lookup/BeamLine_Undulator_toGap.txt b/tests/test_data/test_daq_configuration/lookup/BeamLine_Undulator_toGap.txt index 61575edf1b..bb101e0696 100755 --- a/tests/test_data/test_daq_configuration/lookup/BeamLine_Undulator_toGap.txt +++ b/tests/test_data/test_daq_configuration/lookup/BeamLine_Undulator_toGap.txt @@ -1,5 +1,4 @@ { - "column_names": ["energy_eV", "gap_mm"], "rows": [ [5700, 5.4606], [5760, 5.5], From 96e388d819ef2b6bed814e2a09e82fafc8f66a50 Mon Sep 17 00:00:00 2001 From: Jacob Williamson Date: Tue, 6 Jan 2026 14:05:29 +0000 Subject: [PATCH 5/6] Fix for columns becoming a property --- .../device_setup_plans/dcm_pitch_roll_mirror_adjuster.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py b/src/mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py index 72da533e25..5a9e562e1e 100644 --- a/src/mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py +++ b/src/mx_bluesky/hyperion/device_setup_plans/dcm_pitch_roll_mirror_adjuster.py @@ -123,7 +123,7 @@ def adjust_dcm_pitch_roll_vfm_from_lut( bragg_deg = energy_to_bragg_angle(energy_kev, d_spacing_a) LOGGER.info(f"Target Bragg angle = {bragg_deg} degrees") dcm_pitch_adjuster = lookup_table_adjuster( - linear_interpolation_lut(*pitch_energy_table.columns()), + linear_interpolation_lut(*pitch_energy_table.columns), dcm.xtal_1.pitch_in_mrad, bragg_deg, ) @@ -136,7 +136,7 @@ def adjust_dcm_pitch_roll_vfm_from_lut( undulator_dcm.roll_energy_table_path, BeamlineRollLookupTable ) dcm_roll_adjuster = lookup_table_adjuster( - linear_interpolation_lut(*roll_energy_table.columns()), + linear_interpolation_lut(*roll_energy_table.columns), dcm.xtal_1.roll_in_mrad, bragg_deg, ) From 70ea107b7739d8ec0ba3daa41a050eef233e77aa Mon Sep 17 00:00:00 2001 From: Jacob Williamson Date: Mon, 12 Jan 2026 12:19:52 +0000 Subject: [PATCH 6/6] Use latest config server version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 4f7c7fb70b..a831d3882f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ dependencies = [ # These dependencies may be issued as pre-release versions and should have a pin constraint # as by default pip-install will not upgrade to a pre-release. # - "daq-config-server @ git+https://github.com/DiamondLightSource/daq-config-server.git@extend_lookup_table_model", + "daq-config-server >= v1.1.2", "blueapi >= 1.8.0", "ophyd >= 1.10.5", "ophyd-async >= 0.14.0",