From 59a5c64efdee455f409c740c0063d0565f2f2bc5 Mon Sep 17 00:00:00 2001 From: Robert Tuck Date: Wed, 17 Jan 2024 13:12:05 +0000 Subject: [PATCH 1/6] (DiamondLightSource/hyperion#1077) Hyperion to populate ispyb resolution instead of GDA * Populate the detector resolution in wait for robot load * Schema changes to allow the detector resolution to not be specified in the request --- .../wait_for_robot_load_then_centre_plan.py | 9 +++++++++ .../external_interaction/ispyb/ispyb_dataclass.py | 3 ++- .../parameters/schemas/ispyb_parameters_schema.json | 3 +-- .../good_test_wait_for_robot_load_params.json | 1 - .../test_wait_for_robot_load_then_centre.py | 7 +++++++ 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/hyperion/experiment_plans/wait_for_robot_load_then_centre_plan.py b/src/hyperion/experiment_plans/wait_for_robot_load_then_centre_plan.py index d537cee39..65092346b 100644 --- a/src/hyperion/experiment_plans/wait_for_robot_load_then_centre_plan.py +++ b/src/hyperion/experiment_plans/wait_for_robot_load_then_centre_plan.py @@ -10,6 +10,7 @@ from dodal.devices.attenuator import Attenuator from dodal.devices.backlight import Backlight from dodal.devices.DCM import DCM +from dodal.devices.det_resolution import resolution from dodal.devices.detector_motion import DetectorMotion from dodal.devices.eiger import EigerDetector from dodal.devices.fast_grid_scan import FastGridScan @@ -49,6 +50,7 @@ from hyperion.parameters.plan_specific.wait_for_robot_load_then_center_params import ( WaitForRobotLoadThenCentreInternalParameters, ) +from hyperion.utils.utils import convert_eV_to_angstrom @dataclasses.dataclass @@ -145,6 +147,13 @@ def wait_for_robot_load_then_centre( parameters.experiment_params.requested_energy_kev * 1000 ) + wavelength_angstroms = convert_eV_to_angstrom(actual_energy_ev) + parameters.hyperion_params.ispyb_params.resolution = resolution( + parameters.hyperion_params.detector_params, + wavelength_angstroms, + parameters.experiment_params.detector_distance, + ) + eiger.set_detector_parameters(parameters.hyperion_params.detector_params) yield from start_preparing_data_collection_then_do_plan( diff --git a/src/hyperion/external_interaction/ispyb/ispyb_dataclass.py b/src/hyperion/external_interaction/ispyb/ispyb_dataclass.py index cc449abf4..408178a80 100644 --- a/src/hyperion/external_interaction/ispyb/ispyb_dataclass.py +++ b/src/hyperion/external_interaction/ispyb/ispyb_dataclass.py @@ -49,7 +49,8 @@ class IspybParams(BaseModel): focal_spot_size_x: float focal_spot_size_y: float comment: str - resolution: float + # populated by wait_for_robot_load_then_centre + resolution: Optional[float] sample_id: Optional[str] = None sample_barcode: Optional[str] = None diff --git a/src/hyperion/parameters/schemas/ispyb_parameters_schema.json b/src/hyperion/parameters/schemas/ispyb_parameters_schema.json index 932ef558f..7dc532e2b 100644 --- a/src/hyperion/parameters/schemas/ispyb_parameters_schema.json +++ b/src/hyperion/parameters/schemas/ispyb_parameters_schema.json @@ -90,7 +90,6 @@ "beam_size_y", "focal_spot_size_x", "focal_spot_size_y", - "comment", - "resolution" + "comment" ] } \ No newline at end of file diff --git a/tests/test_data/parameter_json_files/good_test_wait_for_robot_load_params.json b/tests/test_data/parameter_json_files/good_test_wait_for_robot_load_params.json index f46b09297..5a7a848f4 100644 --- a/tests/test_data/parameter_json_files/good_test_wait_for_robot_load_params.json +++ b/tests/test_data/parameter_json_files/good_test_wait_for_robot_load_params.json @@ -28,7 +28,6 @@ "focal_spot_size_x": 0.0, "focal_spot_size_y": 0.0, "comment": "Descriptive comment.", - "resolution": 1, "sample_id": null, "sample_barcode": null } diff --git a/tests/unit_tests/experiment_plans/test_wait_for_robot_load_then_centre.py b/tests/unit_tests/experiment_plans/test_wait_for_robot_load_then_centre.py index 3ece0191d..9c89b6613 100644 --- a/tests/unit_tests/experiment_plans/test_wait_for_robot_load_then_centre.py +++ b/tests/unit_tests/experiment_plans/test_wait_for_robot_load_then_centre.py @@ -5,6 +5,7 @@ from bluesky.utils import Msg from dodal.devices.eiger import EigerDetector from dodal.devices.smargon import Smargon +from numpy import isclose from ophyd.sim import instantiate_fake_device from hyperion.experiment_plans.wait_for_robot_load_then_centre_plan import ( @@ -79,6 +80,7 @@ def test_when_plan_run_then_centring_plan_run_with_expected_parameters( assert isinstance(params_passed, PinCentreThenXrayCentreInternalParameters) assert params_passed.hyperion_params.detector_params.expected_energy_ev == 11100 assert params_passed.hyperion_params.ispyb_params.current_energy_ev == 11105 + assert isclose(params_passed.hyperion_params.ispyb_params.resolution, 2.11338) @patch( @@ -166,6 +168,11 @@ def return_not_disabled_after_reads(_): num_of_reads += 1 return {"values": {"value": int(num_of_reads < total_disabled_reads)}} + sim_run_engine.add_handler( + "read", + "dcm_energy_in_kev", + lambda msg: {"dcm_energy_in_kev": {"value": 11.105}}, + ) sim_run_engine.add_handler( "read", "smargon_disabled", From 1c2e7e5568244882b840109c2af851f6b401df28 Mon Sep 17 00:00:00 2001 From: Robert Tuck Date: Wed, 17 Jan 2024 13:31:21 +0000 Subject: [PATCH 2/6] (DiamondLightSource/hyperion#1077) make pyright happy --- .../experiment_plans/test_wait_for_robot_load_then_centre.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/unit_tests/experiment_plans/test_wait_for_robot_load_then_centre.py b/tests/unit_tests/experiment_plans/test_wait_for_robot_load_then_centre.py index 9c89b6613..bb1baf6c8 100644 --- a/tests/unit_tests/experiment_plans/test_wait_for_robot_load_then_centre.py +++ b/tests/unit_tests/experiment_plans/test_wait_for_robot_load_then_centre.py @@ -80,7 +80,9 @@ def test_when_plan_run_then_centring_plan_run_with_expected_parameters( assert isinstance(params_passed, PinCentreThenXrayCentreInternalParameters) assert params_passed.hyperion_params.detector_params.expected_energy_ev == 11100 assert params_passed.hyperion_params.ispyb_params.current_energy_ev == 11105 - assert isclose(params_passed.hyperion_params.ispyb_params.resolution, 2.11338) + assert isclose( + params_passed.hyperion_params.ispyb_params.resolution, 2.11338 # type: ignore + ) @patch( From 41be902a03c3101bb068875b9ece44cade16f617 Mon Sep 17 00:00:00 2001 From: Robert Tuck Date: Thu, 25 Jan 2024 14:18:06 +0000 Subject: [PATCH 3/6] (DiamondLightSource/hyperion#1077) Move detector into separate package as per review comment --- .../wait_for_robot_load_then_centre_plan.py | 2 +- .../experiment_plans/test_flyscan_xray_centre_plan.py | 2 +- .../external_interaction/nexus/test_write_nexus.py | 8 ++++---- .../plan_specific/test_fgs_internal_parameters.py | 2 +- ...test_grid_scan_with_edge_detect_internal_parameters.py | 2 +- .../plan_specific/test_rotation_internal_parameters.py | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hyperion/experiment_plans/wait_for_robot_load_then_centre_plan.py b/src/hyperion/experiment_plans/wait_for_robot_load_then_centre_plan.py index 65092346b..fa772f17a 100644 --- a/src/hyperion/experiment_plans/wait_for_robot_load_then_centre_plan.py +++ b/src/hyperion/experiment_plans/wait_for_robot_load_then_centre_plan.py @@ -10,7 +10,7 @@ from dodal.devices.attenuator import Attenuator from dodal.devices.backlight import Backlight from dodal.devices.DCM import DCM -from dodal.devices.det_resolution import resolution +from dodal.devices.detector.det_resolution import resolution from dodal.devices.detector_motion import DetectorMotion from dodal.devices.eiger import EigerDetector from dodal.devices.fast_grid_scan import FastGridScan diff --git a/tests/unit_tests/experiment_plans/test_flyscan_xray_centre_plan.py b/tests/unit_tests/experiment_plans/test_flyscan_xray_centre_plan.py index 46da203f1..760c5f2d9 100644 --- a/tests/unit_tests/experiment_plans/test_flyscan_xray_centre_plan.py +++ b/tests/unit_tests/experiment_plans/test_flyscan_xray_centre_plan.py @@ -7,7 +7,7 @@ import pytest from bluesky import FailedStatus from bluesky.run_engine import RunEngine -from dodal.devices.det_dim_constants import ( +from dodal.devices.detector.det_dim_constants import ( EIGER2_X_4M_DIMENSION, EIGER_TYPE_EIGER2_X_4M, EIGER_TYPE_EIGER2_X_16M, diff --git a/tests/unit_tests/external_interaction/nexus/test_write_nexus.py b/tests/unit_tests/external_interaction/nexus/test_write_nexus.py index 1596b7c7d..e73c19c0b 100644 --- a/tests/unit_tests/external_interaction/nexus/test_write_nexus.py +++ b/tests/unit_tests/external_interaction/nexus/test_write_nexus.py @@ -246,7 +246,7 @@ def test_nexus_writer_files_are_formatted_as_expected( def test_nexus_writer_writes_width_and_height_correctly( single_dummy_file: NexusWriter, ): - from dodal.devices.det_dim_constants import ( + from dodal.devices.detector.det_dim_constants import ( PIXELS_X_EIGER2_X_4M, PIXELS_Y_EIGER2_X_4M, ) @@ -290,21 +290,21 @@ def check_validity_through_zocalo(nexus_writers: tuple[NexusWriter, NexusWriter] @pytest.mark.dlstbx def test_nexus_file_validity_for_zocalo_with_two_linked_datasets( - dummy_nexus_writers: tuple[NexusWriter, NexusWriter] + dummy_nexus_writers: tuple[NexusWriter, NexusWriter], ): check_validity_through_zocalo(dummy_nexus_writers) @pytest.mark.dlstbx def test_nexus_file_validity_for_zocalo_with_three_linked_datasets( - dummy_nexus_writers_with_more_images: tuple[NexusWriter, NexusWriter] + dummy_nexus_writers_with_more_images: tuple[NexusWriter, NexusWriter], ): check_validity_through_zocalo(dummy_nexus_writers_with_more_images) @pytest.mark.skip("Requires #87 of nexgen") def test_given_some_datafiles_outside_of_VDS_range_THEN_they_are_not_in_nexus_file( - dummy_nexus_writers_with_more_images: tuple[NexusWriter, NexusWriter] + dummy_nexus_writers_with_more_images: tuple[NexusWriter, NexusWriter], ): nexus_writer_1, nexus_writer_2 = dummy_nexus_writers_with_more_images diff --git a/tests/unit_tests/parameters/plan_specific/test_fgs_internal_parameters.py b/tests/unit_tests/parameters/plan_specific/test_fgs_internal_parameters.py index d5dd0c466..629ec71e0 100644 --- a/tests/unit_tests/parameters/plan_specific/test_fgs_internal_parameters.py +++ b/tests/unit_tests/parameters/plan_specific/test_fgs_internal_parameters.py @@ -1,5 +1,5 @@ import numpy as np -from dodal.devices.det_dim_constants import EIGER2_X_16M_SIZE +from dodal.devices.detector.det_dim_constants import EIGER2_X_16M_SIZE from dodal.devices.fast_grid_scan import GridScanParams from hyperion.parameters import external_parameters diff --git a/tests/unit_tests/parameters/plan_specific/test_grid_scan_with_edge_detect_internal_parameters.py b/tests/unit_tests/parameters/plan_specific/test_grid_scan_with_edge_detect_internal_parameters.py index 830348226..6cfea9174 100644 --- a/tests/unit_tests/parameters/plan_specific/test_grid_scan_with_edge_detect_internal_parameters.py +++ b/tests/unit_tests/parameters/plan_specific/test_grid_scan_with_edge_detect_internal_parameters.py @@ -1,5 +1,5 @@ import numpy as np -from dodal.devices.det_dim_constants import EIGER2_X_16M_SIZE +from dodal.devices.detector.det_dim_constants import EIGER2_X_16M_SIZE from hyperion.parameters import external_parameters from hyperion.parameters.plan_specific.grid_scan_with_edge_detect_params import ( diff --git a/tests/unit_tests/parameters/plan_specific/test_rotation_internal_parameters.py b/tests/unit_tests/parameters/plan_specific/test_rotation_internal_parameters.py index bfb37a005..8f4955d93 100644 --- a/tests/unit_tests/parameters/plan_specific/test_rotation_internal_parameters.py +++ b/tests/unit_tests/parameters/plan_specific/test_rotation_internal_parameters.py @@ -2,7 +2,7 @@ import numpy as np import pytest -from dodal.devices.det_dim_constants import EIGER2_X_16M_SIZE +from dodal.devices.detector.det_dim_constants import EIGER2_X_16M_SIZE from dodal.devices.motors import XYZLimitBundle from hyperion.parameters import external_parameters From e616a79347c9aaa1a06b71680bf02d8741e3c1fd Mon Sep 17 00:00:00 2001 From: Robert Tuck Date: Mon, 29 Jan 2024 09:59:40 +0000 Subject: [PATCH 4/6] (DiamondLightSource/hyperionDiamondLightSource/hyperion#1077) Fixups after rebasing --- .../experiment_plans/test_panda_flyscan_xray_centre_plan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit_tests/experiment_plans/test_panda_flyscan_xray_centre_plan.py b/tests/unit_tests/experiment_plans/test_panda_flyscan_xray_centre_plan.py index 35798c86f..8607d364f 100644 --- a/tests/unit_tests/experiment_plans/test_panda_flyscan_xray_centre_plan.py +++ b/tests/unit_tests/experiment_plans/test_panda_flyscan_xray_centre_plan.py @@ -6,7 +6,7 @@ import numpy as np import pytest from bluesky.run_engine import RunEngine -from dodal.devices.det_dim_constants import ( +from dodal.devices.detector.det_dim_constants import ( EIGER2_X_4M_DIMENSION, EIGER_TYPE_EIGER2_X_4M, EIGER_TYPE_EIGER2_X_16M, From 70e29c9722e98ea73fc57375ae1abf49b45647d6 Mon Sep 17 00:00:00 2001 From: Robert Tuck Date: Mon, 29 Jan 2024 10:25:19 +0000 Subject: [PATCH 5/6] (DiamondLightSource/hyperion#1077) Move detector_motion.py into detector package as per review comment --- setup.cfg | 2 +- src/hyperion/device_setup_plans/manipulate_sample.py | 2 +- src/hyperion/device_setup_plans/position_detector.py | 2 +- src/hyperion/device_setup_plans/utils.py | 2 +- .../experiment_plans/grid_detect_then_xray_centre_plan.py | 4 +--- src/hyperion/experiment_plans/rotation_scan_plan.py | 3 +-- .../experiment_plans/wait_for_robot_load_then_centre_plan.py | 2 +- tests/conftest.py | 2 +- tests/system_tests/experiment_plans/test_rotation_plan.py | 2 +- .../experiment_plans/test_pin_centre_then_xray_centre_plan.py | 2 +- 10 files changed, 10 insertions(+), 13 deletions(-) diff --git a/setup.cfg b/setup.cfg index 8feb4ce6c..1485b4e19 100644 --- a/setup.cfg +++ b/setup.cfg @@ -35,7 +35,7 @@ install_requires = xarray doct databroker - dls-dodal @ git+https://github.com/DiamondLightSource/dodal.git@a5228493da48b24a09bb9ff2d1fd1ef8c69d8c71 + dls-dodal @ git+https://github.com/DiamondLightSource/dodal.git@54af3ccf31a1570dc4bdb0d365f8696a3d130d92 pydantic<2.0 # See https://github.com/DiamondLightSource/hyperion/issues/774 scipy pyzmq<25 # See https://github.com/DiamondLightSource/hyperion/issues/1103 diff --git a/src/hyperion/device_setup_plans/manipulate_sample.py b/src/hyperion/device_setup_plans/manipulate_sample.py index c2be3d723..d0f60544c 100644 --- a/src/hyperion/device_setup_plans/manipulate_sample.py +++ b/src/hyperion/device_setup_plans/manipulate_sample.py @@ -3,7 +3,7 @@ import bluesky.plan_stubs as bps from dodal.devices.attenuator import Attenuator from dodal.devices.backlight import Backlight -from dodal.devices.detector_motion import DetectorMotion +from dodal.devices.detector.detector_motion import DetectorMotion from dodal.devices.smargon import Smargon from hyperion.log import LOGGER diff --git a/src/hyperion/device_setup_plans/position_detector.py b/src/hyperion/device_setup_plans/position_detector.py index d4a3b0c2a..d40482617 100644 --- a/src/hyperion/device_setup_plans/position_detector.py +++ b/src/hyperion/device_setup_plans/position_detector.py @@ -1,5 +1,5 @@ from bluesky import plan_stubs as bps -from dodal.devices.detector_motion import DetectorMotion, ShutterState +from dodal.devices.detector.detector_motion import DetectorMotion, ShutterState from hyperion.log import LOGGER diff --git a/src/hyperion/device_setup_plans/utils.py b/src/hyperion/device_setup_plans/utils.py index c271f65ea..01dad7821 100644 --- a/src/hyperion/device_setup_plans/utils.py +++ b/src/hyperion/device_setup_plans/utils.py @@ -3,7 +3,7 @@ from bluesky import plan_stubs as bps from bluesky import preprocessors as bpp from bluesky.utils import Msg -from dodal.devices.detector_motion import DetectorMotion, ShutterState +from dodal.devices.detector.detector_motion import DetectorMotion, ShutterState from dodal.devices.eiger import EigerDetector from hyperion.device_setup_plans.position_detector import ( diff --git a/src/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py b/src/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py index 6993dabd8..a35073ab7 100644 --- a/src/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +++ b/src/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py @@ -12,14 +12,13 @@ from dodal.devices.attenuator import Attenuator from dodal.devices.backlight import Backlight from dodal.devices.DCM import DCM -from dodal.devices.detector_motion import DetectorMotion +from dodal.devices.detector.detector_motion import DetectorMotion from dodal.devices.eiger import EigerDetector from dodal.devices.fast_grid_scan import FastGridScan from dodal.devices.flux import Flux from dodal.devices.oav.oav_detector import OAV from dodal.devices.oav.oav_parameters import OAV_CONFIG_JSON, OAVParameters from dodal.devices.oav.pin_image_recognition import PinTipDetection -from dodal.devices.panda_fast_grid_scan import PandAGridScanParams from dodal.devices.robot import BartRobot from dodal.devices.s4_slit_gaps import S4SlitGaps from dodal.devices.smargon import Smargon @@ -33,7 +32,6 @@ start_preparing_data_collection_then_do_plan, ) from hyperion.experiment_plans.flyscan_xray_centre_plan import ( - FlyScanXRayCentreComposite, flyscan_xray_centre, ) from hyperion.experiment_plans.oav_grid_detection_plan import ( diff --git a/src/hyperion/experiment_plans/rotation_scan_plan.py b/src/hyperion/experiment_plans/rotation_scan_plan.py index 05ee189a3..7e6f19354 100644 --- a/src/hyperion/experiment_plans/rotation_scan_plan.py +++ b/src/hyperion/experiment_plans/rotation_scan_plan.py @@ -9,8 +9,7 @@ from dodal.devices.attenuator import Attenuator from dodal.devices.backlight import Backlight from dodal.devices.DCM import DCM -from dodal.devices.detector import DetectorParams -from dodal.devices.detector_motion import DetectorMotion +from dodal.devices.detector.detector_motion import DetectorMotion from dodal.devices.eiger import EigerDetector from dodal.devices.flux import Flux from dodal.devices.robot import BartRobot diff --git a/src/hyperion/experiment_plans/wait_for_robot_load_then_centre_plan.py b/src/hyperion/experiment_plans/wait_for_robot_load_then_centre_plan.py index fa772f17a..5f2e3e714 100644 --- a/src/hyperion/experiment_plans/wait_for_robot_load_then_centre_plan.py +++ b/src/hyperion/experiment_plans/wait_for_robot_load_then_centre_plan.py @@ -11,7 +11,7 @@ from dodal.devices.backlight import Backlight from dodal.devices.DCM import DCM from dodal.devices.detector.det_resolution import resolution -from dodal.devices.detector_motion import DetectorMotion +from dodal.devices.detector.detector_motion import DetectorMotion from dodal.devices.eiger import EigerDetector from dodal.devices.fast_grid_scan import FastGridScan from dodal.devices.flux import Flux diff --git a/tests/conftest.py b/tests/conftest.py index b186547fb..30251550c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -13,7 +13,7 @@ from dodal.devices.attenuator import Attenuator from dodal.devices.backlight import Backlight from dodal.devices.DCM import DCM -from dodal.devices.detector_motion import DetectorMotion +from dodal.devices.detector.detector_motion import DetectorMotion from dodal.devices.eiger import EigerDetector from dodal.devices.fast_grid_scan import GridScanCompleteStatus from dodal.devices.flux import Flux diff --git a/tests/system_tests/experiment_plans/test_rotation_plan.py b/tests/system_tests/experiment_plans/test_rotation_plan.py index debb0ce07..d722e99dd 100644 --- a/tests/system_tests/experiment_plans/test_rotation_plan.py +++ b/tests/system_tests/experiment_plans/test_rotation_plan.py @@ -14,7 +14,7 @@ if TYPE_CHECKING: from dodal.devices.backlight import Backlight # noqa - from dodal.devices.detector_motion import DetectorMotion # noqa + from dodal.devices.detector.detector_motion import DetectorMotion # noqa from dodal.devices.eiger import EigerDetector # noqa from dodal.devices.smargon import Smargon from dodal.devices.zebra import Zebra # noqa diff --git a/tests/unit_tests/experiment_plans/test_pin_centre_then_xray_centre_plan.py b/tests/unit_tests/experiment_plans/test_pin_centre_then_xray_centre_plan.py index dad95c46a..7b41a25ab 100644 --- a/tests/unit_tests/experiment_plans/test_pin_centre_then_xray_centre_plan.py +++ b/tests/unit_tests/experiment_plans/test_pin_centre_then_xray_centre_plan.py @@ -3,7 +3,7 @@ import pytest from bluesky.run_engine import RunEngine from bluesky.utils import Msg -from dodal.devices.detector_motion import ShutterState +from dodal.devices.detector.detector_motion import ShutterState from hyperion.experiment_plans.pin_centre_then_xray_centre_plan import ( create_parameters_for_grid_detection, From 25dc2c7954a4f70a8a6136991f6d2739bc307f6c Mon Sep 17 00:00:00 2001 From: Robert Tuck Date: Fri, 1 Mar 2024 09:30:43 +0000 Subject: [PATCH 6/6] (DiamondLightSource/hyperion#1077) Fix broken import --- src/hyperion/experiment_plans/rotation_scan_plan.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hyperion/experiment_plans/rotation_scan_plan.py b/src/hyperion/experiment_plans/rotation_scan_plan.py index 7e6f19354..1a4a4344d 100644 --- a/src/hyperion/experiment_plans/rotation_scan_plan.py +++ b/src/hyperion/experiment_plans/rotation_scan_plan.py @@ -9,6 +9,7 @@ from dodal.devices.attenuator import Attenuator from dodal.devices.backlight import Backlight from dodal.devices.DCM import DCM +from dodal.devices.detector import DetectorParams from dodal.devices.detector.detector_motion import DetectorMotion from dodal.devices.eiger import EigerDetector from dodal.devices.flux import Flux