From 102d69966fcef7f3fdb18437f1a8831734733fa3 Mon Sep 17 00:00:00 2001
From: Karim Ahmed <karim.ahmed@xfel.eu>
Date: Mon, 30 Nov 2020 09:45:43 +0100
Subject: [PATCH] [AGIPD][CORRECT] New PC data sanitization

---
 cal_tools/cal_tools/agipdlib.py | 74 +++++++++++++++++++++------------
 1 file changed, 48 insertions(+), 26 deletions(-)

diff --git a/cal_tools/cal_tools/agipdlib.py b/cal_tools/cal_tools/agipdlib.py
index 18328ff08..573588c58 100644
--- a/cal_tools/cal_tools/agipdlib.py
+++ b/cal_tools/cal_tools/agipdlib.py
@@ -556,18 +556,20 @@ class AgipdCorrections:
             data *= rel_cor
             del rel_cor
 
-        # Set negative values for medium gain to 0
-        if self.corr_bools.get('blc_set_min'):
-            data[(data < 0) & (gain == 1)] = 0
-
         # Adjust medium gain baseline to match highest high gain value
         if self.corr_bools.get("adjust_mg_baseline"):
             mgbc = self.md_additional_offset[module_idx][cellid, ...]
             data[gain == 1] += mgbc[gain == 1]
             del mgbc
 
-        # Do xray correction if requested 
-        # The slopes we have in our constants are already relative
+        # Set negative values for medium gain to 0
+        # TODO: Probably it would be better to add it to badpixel maps,
+        # not just set to 0
+        if self.corr_bools.get('blc_set_min'):
+            data[(data < 0) & (gain == 1)] = 0
+            
+        # Do xray correction if requested
+        # The slopes we have in our constants are already relative 
         # slopeFF = slopeFFpix/avarege(slopeFFpix)
         # To apply them we have to / not *
         if self.corr_bools.get("xray_corr"):
@@ -857,11 +859,10 @@ class AgipdCorrections:
           Please note: Current slopesFF avaialble in calibibration
           constants are created per pixel only, not per memory cell:
 
+
              rel_high_gain = 1 if only PC data is available
              rel_high_gain = rel_slopesFF if FF data is also available
 
-          
-
         * Relative gain for Medium gain stage: we derive the factor
           between high and medium gain using slope information from
           fits to the linear part of high and medium gain:
@@ -948,38 +949,59 @@ class AgipdCorrections:
             pc_med_m = slopesPC[..., :self.max_cells, 3]
             pc_med_l = slopesPC[..., :self.max_cells, 4]
 
-            # calculate ratio high to medium gain 
-            pc_high_ave = np.nanmean(pc_high_m, axis=(0,1))
-            pc_med_ave = np.nanmean(pc_med_m, axis=(0,1))
-            # ration between HG and MG per pixel per mem cell 
-            # used for rel gain calculation
+            # calculate median for slopes  
+            pc_high_med = np.nanmedian(pc_high_m, axis=(0,1))
+            pc_med_med = np.nanmedian(pc_med_m, axis=(0,1))
+            # calculate median for intercepts:
+            pc_high_l_med = np.nanmedian(pc_high_l, axis=(0,1))
+            pc_med_l_med = np.nanmedian(pc_med_l, axis=(0,1))
+            
+            # sanitize PC data 
+            # (it should be done already on the level of constants)
+            # In the following loop, 
+            # replace `nan`s across memory cells with
+            # the median value calculated previously.
+            # Then, values outside of the valid range (0.8 and 1.2)
+            # are fixed to the median value.
+            # This is applied for high and medium gain stages
+            for i in range(self.max_cells):
+                pc_high_m[np.isnan(pc_high_m[..., i])] = pc_high_med[i]
+                pc_med_m[np.isnan(pc_med_m[..., i])] = pc_med_med[i]
+
+                pc_high_l[np.isnan(pc_high_l[..., i])] = pc_high_l_med[i]
+                pc_med_l[np.isnan(pc_med_l[..., i])] = pc_med_l_med[i]
+
+                pc_high_m[(pc_high_m[..., i] < 0.8 * pc_high_med[i]) |
+                          (pc_high_m[..., i] > 1.2 * pc_high_med[i])] = pc_high_med[i]  # noqa
+                pc_med_m[(pc_med_m[..., i] < 0.8 * pc_med_med[i]) |
+                         (pc_med_m[..., i] > 1.2 * pc_med_med[i])] = pc_med_med[i]  # noqa
+
+                pc_high_l[(pc_high_l[..., i] < 0.8 * pc_high_l_med[i]) |
+                          (pc_high_l[..., i] > 1.2 * pc_high_l_med[i])] = pc_high_l_med[i]  # noqa
+                pc_med_l[(pc_med_l[..., i] < 0.8 * pc_med_l_med[i]) |
+                         (pc_med_l[..., i] > 1.2 * pc_med_l_med[i])] = pc_med_l_med[i]  # noqa
+
+            # ration between HG and MG per pixel per mem cell used
+            # for rel gain calculation
             frac_high_med_pix = pc_high_m / pc_med_m
             # avarage ration between HG and MG as a function of 
             # mem cell (needed for bls_stripes)
             # TODO: Per pixel would be more optimal correction
-            frac_high_med = pc_high_ave / pc_med_ave
+            frac_high_med = pc_high_med / pc_med_med
             # calculate additional medium-gain offset
             md_additional_offset = pc_high_l - pc_med_l * pc_high_m / pc_med_m
 
-            # Calculate relative gain. If FF constants are available,
-            # use them for high gain
-            # if not rel_gain is calculated using PC data only
-            # if self.corr_bools.get("xray_corr"):
-            #     rel_gain[..., :self.max_cells, 0] /= xray_corr 
-
-            # PC data should be 'calibrated with X-ray data, 
-            # if it is not done, it is better to use 1 instead of bias 
-            # the results with PC arteffacts. 
+            # PC data should be 'calibrated with X-ray data,
+            # if it is not done, it is better to use 1 instead of bias
+            # the results with PC arteffacts.
             # rel_gain[..., 0] = 1./(pc_high_m / pc_high_ave)
-
-            # High-gain (rel_gain[..., 0]) stays the same
             rel_gain[..., 1] = rel_gain[..., 0] * frac_high_med_pix
             rel_gain[..., 2] = rel_gain[..., 1] * 4.48
 
             self.md_additional_offset[module_idx][...] = md_additional_offset.transpose()[...]  # noqa
             self.rel_gain[module_idx][...] = rel_gain[...].transpose()
             self.frac_high_med[module_idx][...] = frac_high_med
-            
+
         self.mask[module_idx][...] = bpixels.transpose()[...]
 
         return
-- 
GitLab