diff --git a/notebooks/AGIPD/Characterize_AGIPD_Gain_Darks_NBC.ipynb b/notebooks/AGIPD/Characterize_AGIPD_Gain_Darks_NBC.ipynb
index ba2a74c76b9b1db27cc42e5873b42424d5054450..36d88640f1fb95559d49b23eb2e5ccd114342da9 100644
--- a/notebooks/AGIPD/Characterize_AGIPD_Gain_Darks_NBC.ipynb
+++ b/notebooks/AGIPD/Characterize_AGIPD_Gain_Darks_NBC.ipynb
@@ -96,7 +96,7 @@
     "from collections import OrderedDict\n",
     "from datetime import timedelta\n",
     "from pathlib import Path\n",
-    "from typing import List, Tuple\n",
+    "from typing import Tuple\n",
     "\n",
     "import matplotlib\n",
     "import numpy as np\n",
@@ -142,16 +142,8 @@
     "# insert control device if format string (does nothing otherwise)\n",
     "ctrl_src = ctrl_source_template.format(karabo_id_control)\n",
     "\n",
-    "runs_dict = OrderedDict()\n",
     "run_numbers = [run_high, run_med, run_low]\n",
     "\n",
-    "for gain_idx, (run_name, run_number) in enumerate(zip([\"high\", \"med\", \"low\"], run_numbers)):\n",
-    "    runs_dict[run_name] = {\n",
-    "        \"number\": run_number,\n",
-    "        \"gain\": gain_idx,\n",
-    "        \"dc\": RunDirectory(f'{in_folder}/r{run_number:04d}/')\n",
-    "    }\n",
-    "\n",
     "creation_time=None\n",
     "if use_dir_creation_date:\n",
     "    creation_time = get_dir_creation_date(in_folder, run_high)\n",
@@ -206,35 +198,35 @@
     "Path(out_folder).mkdir(parents=True, exist_ok=True)\n",
     "\n",
     "mod_image_size = []\n",
-    "for run_dict in runs_dict.values():\n",
+    "for run in run_numbers:\n",
     "    missing_modules = []  # modules with no images within a run.\n",
     "    n_trains_list = []   # list of the number of trains for each module within a run.\n",
     "    # This is important in case of no slurm parallelization over modules is done.\n",
     "    # (e.g. running notebook interactively)\n",
     "    for m in modules:\n",
     "        # validate that there are trains for the selected modules and run.\n",
-    "        dc = run_dict[\"dc\"].select(\n",
+    "        dc = RunDirectory(f'{in_folder}/r{run:04d}/').select(\n",
     "            instrument_src.format(m), \"*\", require_all=True)\n",
     "        n_trains = len(dc.train_ids)\n",
     "\n",
     "        if n_trains == 0:\n",
-    "            print(f\"WARNING: No images for module AGIPD{m:02d}, run {run_dict['number']}.\")\n",
+    "            print(f\"WARNING: No images for module AGIPD{m:02d}, run {run}.\")\n",
     "            missing_modules.append(m)\n",
     "        # Raise a warning if the module has less trains than expected.\n",
     "        elif n_trains < min_trains:\n",
-    "            print(f\"WARNING: AGIPD{m:02d}, run {run_dict['number']} \"\n",
+    "            print(f\"WARNING: AGIPD{m:02d}, run {run} \"\n",
     "                  f\"has trains less than minimum trains: {min_trains}.\")\n",
     "        else:\n",
     "            print(f\"Processing {max_trains if max_trains < n_trains else n_trains} \"\n",
-    "                  f\"for AGIPD{m:02d}, run {run_dict['number']} \")\n",
+    "                  f\"for AGIPD{m:02d}, run {run} \")\n",
     "\n",
     "        n_trains_list.append(n_trains)\n",
     "        mod_image_size.append(np.product(dc[instrument_src.format(m), \"image.data\"].shape) * 2  / 1e9)\n",
     "\n",
     "    if max(n_trains_list) == 0:\n",
-    "        raise ValueError(f\"No images to process for run: {run_dict['number']}\")\n",
+    "        raise ValueError(f\"No images to process for run: {run}\")\n",
     "    elif max(n_trains_list) < min_trains:\n",
-    "        raise ValueError(f\"{run_dict['number']} has less than minimum trains: {min_trains}\")\n",
+    "        raise ValueError(f\"{run} has less than minimum trains: {min_trains}\")\n",
     "\n",
     "# Update modules and karabo_da lists based on available modules to processes.\n",
     "modules = [m for m in modules if m not in missing_modules]\n",
@@ -265,13 +257,13 @@
     "\n",
     "agipd_ctrl_dark = AgipdCtrlRuns(\n",
     "    raw_folder=in_folder,\n",
-    "    runs=[r[\"number\"] for r in runs_dict.values()],\n",
+    "    runs=run_numbers,\n",
     "    image_src=instrument_src_mod,\n",
     "    ctrl_src=ctrl_src,\n",
+    "    sort_dark_runs_enabled=sort_runs\n",
     ")\n",
-    "if sort_runs:\n",
-    "    agipd_ctrl_dark.sort_dark_runs()\n",
-    "\n",
+    "# Update run_numbers list in case it was sorted.\n",
+    "run_numbers = agipd_ctrl_dark.runs\n",
     "if mem_cells == 0:\n",
     "    mem_cells = agipd_ctrl_dark.get_memory_cells()\n",
     "\n",
@@ -389,16 +381,16 @@
     "print(f\"Will use {parallel_num_procs} processes with {parallel_num_threads} threads each\")\n",
     "\n",
     "def characterize_module(\n",
-    "    channel: int, runs_dict: dict,\n",
+    "    channel: int, gain_run: Tuple[int, int],\n",
     ") -> Tuple[int, int, np.array, np.array, np.array, np.array, np.array]:\n",
     "\n",
+    "    gain_index, run = gain_run\n",
     "    # Select the corresponding module channel.\n",
     "    instrument_src_mod = instrument_src.format(channel)\n",
     "\n",
-    "    run_dc = runs_dict[\"dc\"].select(instrument_src_mod, require_all=True)\n",
+    "    run_dc = RunDirectory(f'{in_folder}/r{run:04d}/').select(instrument_src_mod, require_all=True)\n",
     "    if max_trains != 0:\n",
     "        run_dc = run_dc.select_trains(np.s_[:max_trains])\n",
-    "    gain_index = runs_dict[\"gain\"]\n",
     "\n",
     "    # Read module's image and cellId data.\n",
     "    im = run_dc[instrument_src_mod, \"image.data\"].ndarray()\n",
@@ -481,16 +473,16 @@
    "source": [
     "with multiprocessing.Pool(processes=parallel_num_procs) as pool:\n",
     "    results = pool.starmap(\n",
-    "        characterize_module, itertools.product(modules, list(runs_dict.values())))\n",
+    "        characterize_module, itertools.product(modules, list(enumerate(run_numbers))))\n",
     "\n",
     "# mapped values for processing 2 modules example:\n",
-    "# [\n",
-    "#     0, {\"gain\": 0, \"run_number\": <run-high>, \"dc\": <high-dc>},\n",
-    "#     0, {\"gain\": 1, \"run_number\": <run-med>, \"dc\": <med-dc>},\n",
-    "#     0, {\"gain\": 2, \"run_number\": <run-low>, \"dc\": <low-dc>},\n",
-    "#     1, {\"gain\": 0, \"run_number\": <run-high>, \"dc\": <high-dc>},\n",
-    "#     1, {\"gain\": 1, \"run_number\": <run-med>, \"dc\": <med-dc>},\n",
-    "#     1, {\"gain\": 2, \"run_number\": <run-low>, \"dc\": <low-dc>},\n",
+    "# [(0, (0, 9013))\n",
+    "#     0, (0, run-high),\n",
+    "#     0, (1, run-med),\n",
+    "#     0, (2, run-low),\n",
+    "#     1, (0, run-high),\n",
+    "#     1, (1, run-med),\n",
+    "#     1, (2, run-low),,\n",
     "# ]"
    ]
   },
diff --git a/src/cal_tools/agipdlib.py b/src/cal_tools/agipdlib.py
index d58ac7ae630baa014160d7f026a523e34bd6ab6d..c8ca6e65376823d00f85b61b4a62b729e0e76951 100644
--- a/src/cal_tools/agipdlib.py
+++ b/src/cal_tools/agipdlib.py
@@ -308,6 +308,7 @@ class AgipdCtrlRuns:
     runs: List[int]
     image_src: str
     ctrl_src: str
+    sort_dark_runs_enabled: bool = True
 
     adaptive_gain_modes = [AgipdGainMode.ADAPTIVE_GAIN] * 3
     fixed_gain_modes = [
@@ -325,6 +326,8 @@ class AgipdCtrlRuns:
                 ctrl_src=self.ctrl_src,
                 ) for r in self.runs]
         self.gain_modes = self.get_gain_modes()
+        if self.sort_dark_runs_enabled:
+            self.sort_dark_runs()
 
     def _validate_same_value(self, name, values):
             if len(set(values)) != 1:
@@ -375,6 +378,7 @@ class AgipdCtrlRuns:
             # Update run_ctrls and runs order
             self.runs = list(sorted_runs)
             self.run_ctrls = list(sorted_run_ctrls)
+            self.gain_modes = self.get_gain_modes()
 
     def fixed_gain_mode(self):
         """Check if runs are in fixed gain mode.