diff --git a/notebooks/Jungfrau/Jungfrau_dark_analysis_all_gains_burst_mode_NBC.ipynb b/notebooks/Jungfrau/Jungfrau_dark_analysis_all_gains_burst_mode_NBC.ipynb index e8315d3d3cfef1668f67b87d5bd71e46a9957c2c..a630399b4c2fef517205dfe0ba31d58de3579a5a 100644 --- a/notebooks/Jungfrau/Jungfrau_dark_analysis_all_gains_burst_mode_NBC.ipynb +++ b/notebooks/Jungfrau/Jungfrau_dark_analysis_all_gains_burst_mode_NBC.ipynb @@ -167,12 +167,18 @@ "\n", "ctrl_src = ctrl_source_template.format(karabo_id_control)\n", "\n", + "run_nums = jungfraulib.sort_runs_by_gain(\n", + " raw_folder=in_folder,\n", + " runs=run_nums,\n", + " ctrl_src=ctrl_src,\n", + " )\n", + "\n", "for gain, run_n in enumerate(run_nums):\n", " run_dc = RunDirectory(f\"{in_folder}/r{run_n:04d}/\")\n", " gain_runs[run_n] = [gain, run_dc]\n", " ctrl_data = jungfraulib.JungfrauCtrl(run_dc, ctrl_src)\n", " # Read control data for the high gain run only.\n", - " if run_n == run_high:\n", + " if gain == 0:\n", "\n", " run_mcells, sc_start = ctrl_data.get_memory_cells()\n", "\n", @@ -195,20 +201,6 @@ " gain_mode = ctrl_data.get_gain_mode()\n", " med_low_settings.append(ctrl_data.run_mode)\n", "\n", - "# A transperent workaround for old raw data with wrong/missing medium and low settings\n", - "if med_low_settings == [None, None]:\n", - " warning(\"run.settings is not stored in the data to read. \"\n", - " f\"Hence assuming gain_mode = {gain_mode} for adaptive old data.\")\n", - "elif med_low_settings == [\"dynamicgain\", \"forceswitchg1\"]:\n", - " warning(f\"run.settings for medium and low gain runs are wrong {med_low_settings}. \"\n", - " f\"This is an expected bug for old raw data. Setting gain_mode to {gain_mode}.\")\n", - "# Validate that low_med_settings is not a mix of adaptive and fixed settings.\n", - "elif not (sorted(med_low_settings) in [fixed_settings, dynamic_settings, old_fixed_settings]): # noqa\n", - " raise ValueError(\n", - " \"Medium and low run settings are not as expected. \"\n", - " f\"Either {dynamic_settings}, {fixed_settings}, or {old_fixed_settings} are expected.\\n\"\n", - " f\"Got {sorted(med_low_settings)} for both runs, respectively.\")\n", - "\n", "print(f\"Gain mode is {gain_mode} ({med_low_settings})\")\n", "\n", "step_timer.done_step(f'Reading control data.')" diff --git a/src/cal_tools/enums.py b/src/cal_tools/enums.py index eeebf151d8582255a1f66ce77a3c58c303590a7b..94c8dccea76265290f317aecf4f88eb473b90612 100644 --- a/src/cal_tools/enums.py +++ b/src/cal_tools/enums.py @@ -48,7 +48,6 @@ class AgipdGainMode(IntEnum): class JungfrauSettings(Enum): """Jungfrau run gain settings.""" - # old setting, new setting, new mode GAIN_0 = "gain0" HIGH_GAIN_0 = "highgain0" diff --git a/src/cal_tools/jungfraulib.py b/src/cal_tools/jungfraulib.py index fdfdb0bd571099514de806dbbcc69674e4cdf63e..bb1fcbcfa14439eb965d84cae47785a09725ffb0 100644 --- a/src/cal_tools/jungfraulib.py +++ b/src/cal_tools/jungfraulib.py @@ -1,8 +1,10 @@ -from typing import Optional, Tuple +from logging import warning +from typing import Tuple import extra_data -from cal_tools.enums import JungfrauGainMode, JungfrauSettings +from cal_tools.enums import JungfrauGainMode as JGM +from cal_tools.enums import JungfrauSettings def _old_settings_to_new(settings: str, index: int) -> str: @@ -98,22 +100,112 @@ class JungfrauCtrl(): else: # JungfrauSettings.GAIN_0 return 0 - def get_gain_mode(self) -> int: - """Get gain mode value. Fixed `1` or Adaptive `1`. - - `0` if run_mode = dynamic, forceswitchg1, forceswitchg2, or None. - - `1` if run_mode = fixg1 or fixg2. - """ + def get_gain_mode_str(self): # Check if run_mode is of an old settings to convert # into new mode value. - if self.run_mode in [m.value for m in JungfrauGainMode]: - mode = self.run_mode + if self.run_mode in [m.value for m in JGM]: + return self.run_mode else: - mode = _old_settings_to_new(self.run_mode, 1) - - if mode in [ - JungfrauGainMode.FIX_GAIN_1.value, - JungfrauGainMode.FIX_GAIN_2.value, - ]: + return _old_settings_to_new(self.run_mode, 1) + + def get_gain_mode(self) -> int: + """Get gain mode value. Fixed `1` or Adaptive `0`. + Returns: + (int): gain mode parameter condition + """ + gm_enum = self.get_gain_mode_str() + + if gm_enum in [JGM.FIX_GAIN_1.value, JGM.FIX_GAIN_2.value]: return 1 - else: # DYNAMIC, FORCE_SWITCH_G1, or FORCE_SWITCH_G2 + else: # DYNAMIC, FORCE_SWITCH_G1, FORCE_SWITCH_G2 or None return 0 + + +MODES_ORDER = { + JGM.DYNAMIC.value: 0, + JGM.FORCE_SWITCH_HG1.value: 1, + JGM.FORCE_SWITCH_HG2.value: 2, + JGM.FIX_GAIN_1.value: 3, + JGM.FIX_GAIN_2.value: 4, +} +EXPECTED_RUN_ORDER = [ + [ # Adaptive operation mode pattern + JGM.DYNAMIC.value, + JGM.FORCE_SWITCH_HG1.value, + JGM.FORCE_SWITCH_HG2.value + ], + [ # Fixed operation mode pattern + JGM.DYNAMIC.value, + JGM.FIX_GAIN_1.value, + JGM.FIX_GAIN_2.value + ], +] + + +def sort_runs_by_gain( + raw_folder, + runs, + ctrl_src, + modes_order=MODES_ORDER, + expected_run_order=EXPECTED_RUN_ORDER +): + """Validate the 3 dark runs given for Jungfrau. + + Args: + raw_folder (str): RAW folder for the validated dark runs. + runs (list): [High run, Medium run, Low run]. + ctrl_src (str): Control source path for slow data. + modes_order (dict): Gain modes order to sort the runs by. + expected_run_order (list):Expected dark runs order to process. + Raises: + ValueError: Wrong given dark runs + """ + assert len(runs) == 3, "Wrong number of runs. expected a list of 3 runs." + + run_gm_mapping = dict() + for run in runs: + ctrl_data = JungfrauCtrl( + extra_data.RunDirectory(f"{raw_folder}/r{run:04d}/"), + ctrl_src) + gm = ctrl_data.get_gain_mode_str() + run_gm_mapping[run] = gm + + # 1st legacy case before having run.settings in data. + if all(value is None for value in run_gm_mapping.values()): + warning("run.settings is not stored in the data " + f"to read. Hence assuming gain_mode = {gm}" + " for adaptive old data.") + return runs + + run_gm_mapping = dict(sorted( + run_gm_mapping.items(), + key=lambda item: modes_order[item[1]] + )) + if list(run_gm_mapping.keys()) != runs: + warning("Given dark runs are unsorted. " + f"Runs will be sorted from {runs} of gain modes " + f"{list(run_gm_mapping.values())} to " + f"{list(run_gm_mapping.keys())}") + + runs = list(run_gm_mapping.keys()) + modes = list(run_gm_mapping.values()) + + legacy_adaptive = [ + JGM.DYNAMIC.value, + JGM.DYNAMIC.value, + JGM.FORCE_SWITCH_HG1.value + ] + + # 2nd legacy case with CTRL/MDL bug resulting in wrong run settings. + if modes == legacy_adaptive: + warning(f"run.settings for medium and low gain runs" + f" are wrong {modes[1:]}. This is an expected " + f"bug for old raw data. " + "Assuming this is an adaptive gain runs.") + elif not modes in expected_run_order: + raise ValueError("Wrong dark runs are given. " + f"The given three runs are {runs} with " + f"wrong gain modes {modes}." + "Please verify the selected 3 dark runs to process.") + + return runs diff --git a/tests/test_jungfraulib.py b/tests/test_jungfraulib.py index eb7580ad72beaf422871516340648c754b59eaa1..c7fb5258ba2c0035cbad2668e4bdc35131866855 100644 --- a/tests/test_jungfraulib.py +++ b/tests/test_jungfraulib.py @@ -1,7 +1,7 @@ import pytest from extra_data import RunDirectory -from cal_tools.jungfraulib import JungfrauCtrl +from cal_tools.jungfraulib import JungfrauCtrl, sort_runs_by_gain # TODO: replace with mocked RAW data as in tests/test_agipdlib.py JF = JungfrauCtrl( @@ -45,3 +45,22 @@ def test_get_gain_setting(settings, result): def test_get_gain_mode(mode, result): JF.run_mode = mode assert JF.get_gain_mode() == result + +@pytest.mark.parametrize( + 'original_runs,sorted_runs', + [ + ([9035, 9036, 9037], [9035, 9036, 9037]), + ([9035, 9037, 9036], [9035, 9036, 9037]), + ([9033, 9032, 9031], [9031, 9032, 9033]), + ([9033, 9031, 9032], [9031, 9032, 9033]), + ] +) +# TODO: missing fixed gain dark runs for JUNGFRAU from test proposal. +# TODO: missing fixed and adaptive runs after the JF control updated. +def test_sort_runs_by_gain(original_runs, sorted_runs): + raw_folder = "/gpfs/exfel/exp/CALLAB/202130/p900203/raw" + validated_runs = sort_runs_by_gain( + raw_folder=raw_folder, + runs=original_runs, + ctrl_src="FXE_XAD_JF1M/DET/CONTROL") + assert validated_runs == sorted_runs diff --git a/tests/test_reference_runs/callab_tests.py b/tests/test_reference_runs/callab_tests.py index e24e48639fd52a2caeba9c09ef0686cc589f898a..9e41d4c7768ca1c3e9f55703d0f6a9ae13290ed2 100644 --- a/tests/test_reference_runs/callab_tests.py +++ b/tests/test_reference_runs/callab_tests.py @@ -379,9 +379,10 @@ automated_test_config = { "out-folder": "{}/{}/{}", # "/gpfs/exfel/exp/HED/202102/p002656/raw" "in-folder": "/gpfs/exfel/exp/CALLAB/202130/p900203/raw", - "run-high": "9039", # Original run: "219", - "run-med": "9040", # Original run: "220", - "run-low": "9041", # Original run: "221", + # The 3 runs are arranged in a wrong way on purpose. + "run-high": "9040", # Original run: "219", + "run-med": "9041", # Original run: "220", + "run-low": "9039", # Original run: "221", "karabo-id": "HED_IA1_JF500K2", "karabo-da": "JNGFR02", },