From 372f6c031bcf5e6a7002b278296061a300e758fd Mon Sep 17 00:00:00 2001
From: Thomas Kluyver <thomas.kluyver@xfel.eu>
Date: Thu, 14 Nov 2024 13:33:56 +0100
Subject: [PATCH] Parameter to drop last frame of each gain stage in LPD
 parallel gain mode

---
 notebooks/LPD/LPDChar_Darks_NBC.ipynb | 53 +++++++++++++++------------
 1 file changed, 29 insertions(+), 24 deletions(-)

diff --git a/notebooks/LPD/LPDChar_Darks_NBC.ipynb b/notebooks/LPD/LPDChar_Darks_NBC.ipynb
index ece0a09e0..8a94df8b1 100644
--- a/notebooks/LPD/LPDChar_Darks_NBC.ipynb
+++ b/notebooks/LPD/LPDChar_Darks_NBC.ipynb
@@ -54,6 +54,8 @@
     "ntrains = 500  # maximum number of trains to use in each gain stage\n",
     "skip_first_ntrains = 10  # Number of first trains to skip\n",
     "min_trains = 370  # minimum number of trains needed for each gain stage\n",
+    "drop_last_frames_parallelgain = 1  # Discard last N frames of each gain stage in parallel gain mode\n",
+    "bad_gain_tolerance_parallelgain = 0.2  # Error if more than this proportion of pixels are in the wrong gain stage in parallel gain mode\n",
     "\n",
     "# Parameters for plotting\n",
     "skip_plots = False  # exit after writing corrected files\n",
@@ -260,31 +262,34 @@
     "    im = im.astype(np.float32)\n",
     "    \n",
     "    if is_parallel_gain:\n",
-    "        # Frames in the transition region between the gain stages\n",
-    "        # often have some pixels in the previous gain stage.\n",
-    "        # The proper way would be to use np.median, but this is\n",
-    "        # significantly more expensive and .mean().round() should\n",
-    "        # give the same result.\n",
-    "        gain_by_frame = gains.mean(axis=(1, 2)).round().astype(np.int32)\n",
-    "        \n",
-    "        num_frames_by_gain = np.bincount(gain_by_frame)\n",
-    "        \n",
-    "        if not np.all(num_frames_by_gain == num_frames_by_gain[0]):\n",
-    "            raise ValueError(f'Unequal number of frames per gain stage '\n",
-    "                             f'in parallel gain: {num_frames_by_gain}')\n",
-    "        elif len(num_frames_by_gain) != 3:\n",
-    "            raise ValueError(f'Parallel gain contains pixels in {len(num_frames_by_gain)} '\n",
-    "                             f'gain stages, expected 3')\n",
-    "        \n",
+    "        if len(cellid_pattern) % 3 != 0:\n",
+    "            raise ValueError(f\"{len(cellid_pattern)} frames per train is not a multiple \"\n",
+    "                             \"of 3, as expected in parallel gain mode\")\n",
+    "\n",
     "        # Always pick cell IDs from high gain,\n",
     "        # as the other gain stages are corrupted.\n",
-    "        cellid = cellid[gain_by_frame == 0]\n",
-    "        \n",
-    "        # By this point the parallel gain assumption is valid.\n",
     "        cellid_pattern = cellid_pattern[:(len(cellid_pattern) // 3)]\n",
-    "        \n",
-    "        # Pick images for the \"right\" gain stage.\n",
-    "        im = im[gain_by_frame == gg]\n",
+    "\n",
+    "        # (trains, gains, frames)\n",
+    "        frame_indexes = np.arange(len(cellid)).reshape(-1, 3, len(cellid_pattern))\n",
+    "\n",
+    "        # The last frame in each gain stage is often bad, so we may drop it\n",
+    "        if drop_last_frames_parallelgain:\n",
+    "            cellid_pattern = cellid_pattern[:-drop_last_frames_parallelgain]\n",
+    "            frame_indexes = frame_indexes[..., :-drop_last_frames_parallelgain]\n",
+    "\n",
+    "        # Cell IDs from high gain, data from the current gain stage\n",
+    "        cellid = cellid[frame_indexes[:, 0].ravel()]\n",
+    "        gains = gains[frame_indexes[:, gg].ravel()]\n",
+    "        im = im[frame_indexes[:, gg].ravel()]\n",
+    "\n",
+    "        if not np.array_equal(cellid, np.tile(cellid_pattern, len(data.train_ids))):\n",
+    "            raise ValueError(\"Memory cells used are not consistent across trains\")\n",
+    "\n",
+    "        wrong_gain_fraction = (gains != gg).mean(axis=(1, 2))  # fraction per frame\n",
+    "        if (wrong_gain_fraction > bad_gain_tolerance_parallelgain).any():\n",
+    "            raise ValueError(f\"Frames for gain stage {gg} have up to {wrong_gain_fraction.max()} \"\n",
+    "                             f\"pixels in other gain stages (tolerance {bad_gain_tolerance_parallelgain})\")\n",
     "\n",
     "    elif (gains != gg).any():\n",
     "        raise Exception(f\"Adaptive gain run {run_path} contains pixels \"\n",
@@ -1350,9 +1355,9 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.8.10"
+   "version": "3.11.8"
   }
  },
  "nbformat": 4,
- "nbformat_minor": 2
+ "nbformat_minor": 4
 }
-- 
GitLab