diff --git a/src/cal_tools/agipdalgs.pyx b/src/cal_tools/agipdalgs.pyx index 53766a90604a60771aafdae2d445e085cd2ba818..d582af17f110ea1e0ca3958bebffb2929a18499d 100644 --- a/src/cal_tools/agipdalgs.pyx +++ b/src/cal_tools/agipdalgs.pyx @@ -147,69 +147,79 @@ def gain_choose(cnp.ndarray[cnp.uint8_t, ndim=3] a, cnp.ndarray[choices_t, ndim= @boundscheck(False) @wraparound(False) -def sum_and_count_in_range_asic(float[:, :, :] arr, long[:] ix, - float lower, float upper): - """ - Return the sum & count of values where lower <= x <= upper, - across axes 2 & 3 (pixels within an ASIC, as reshaped by AGIPD correction code). - Specialised function for performance. - """ - cdef int i, j, k, l, m +def cm_correction_1pass(float[:, :, :] arr, unsigned short[:] cellid, + float lower, float upper, float fraction): + """Apply 1 pass of common mode correction""" + cdef long long nfrm = arr.shape[0] + cdef long long nx = arr.shape[1] + cdef long long ny = arr.shape[2] + + cdef float asic_thr = fraction * nx * ny + + cdef double[:, :, :] crng_sum = np.zeros([11, nx, ny], dtype=np.float64) + cdef long long[:, :, :] crng_cnt = np.zeros([11, nx, ny], dtype=np.int64) + cdef long long[:, :, :] crng_tot = np.zeros([11, nx, ny], dtype=np.int64) + + cdef long long asic_cnt, cnt, tot, i, l, m + cdef int row + cdef double asic_sum cdef float value - - cdef int nfrm = ix.size - cdef int nx = arr.shape[1] - cdef int ny = arr.shape[2] - - # Drop axes -2 & -1 (pixel dimensions within each ASIC) - count_arr = np.zeros(nfrm, dtype=np.uint64) - sum_arr = np.zeros(nfrm, dtype=np.float64) - - cdef unsigned long long[:] count = count_arr - cdef double[:] sum_ = sum_arr + cdef bint z + cdef bint used_row[11] + with nogil: + for row in range(11): + used_row[row] = False + # sum and count intensities over cell rows and trains + # the result has dimentionality [11, 64, 64] for i in range(nfrm): - k = ix[i] + row = cellid[i] // 32 + used_row[row] = True for l in range(nx): for m in range(ny): - value = arr[k, l, m] - if lower <= value <= upper: - sum_[i] += value - count[i] += 1 - - return sum_arr, count_arr - + value = arr[i, l, m] + z = (lower <= value) and (value <= upper) + crng_sum[row, l, m] += z * value + crng_cnt[row, l, m] += z + crng_tot[row, l, m] += 1 + + # find average values if there are more values in the interval + # than `fraction` + for row in range(11): + if used_row[row]: + for l in range(nx): + for m in range(ny): + tot = crng_tot[row, l, m] + cnt = crng_cnt[row, l, m] + z = cnt < (fraction * tot) + crng_sum[row, l, m] = ( + .0 if z else (crng_sum[row, l, m] / cnt)) + + # substract mean value from the intensities + for i in range(nfrm): + row = cellid[i] // 32 + for l in range(nx): + for m in range(ny): + arr[i, l, m] -= crng_sum[row, l, m] -@boundscheck(False) -@wraparound(False) -def sum_and_count_in_range_cell(float[:, :, :] arr, long[:] ix, - float lower, float upper): - """ - Return the sum & count of values where lower <= x <= upper, - across axes 0 & 1 (memory cells in the same row, as reshaped by AGIPD correction code). - Specialised function for performance. - """ - cdef int i, j, k, l, m - cdef float value - - cdef int nfrm = ix.size - cdef int nx = arr.shape[1] - cdef int ny = arr.shape[2] - - # Drop axes 0 - count_arr = np.zeros([nx, ny], dtype=np.uint64) - sum_arr = np.zeros([nx, ny], dtype=np.float64) - - cdef unsigned long long[:, :] count = count_arr - cdef double[:, :] sum_ = sum_arr - with nogil: + # over ASIC pixels for i in range(nfrm): - k = ix[i] + asic_sum = .0 + asic_cnt = 0 + # sum and count for l in range(nx): for m in range(ny): - value = arr[k, l, m] - if lower <= value <= upper: - sum_[l, m] += value - count[l, m] += 1 + value = arr[i, l, m] + z = (lower <= value) and (value <= upper) + asic_sum += z * value + asic_cnt += z + + # find average values if there are more values in the interval + # than `fraction` + z = asic_cnt < asic_thr + asic_sum = .0 if z else (asic_sum / asic_cnt) - return sum_arr, count_arr + # substract mean value from the intensities + for l in range(nx): + for m in range(ny): + arr[i, l, m] -= asic_sum diff --git a/src/cal_tools/agipdlib.py b/src/cal_tools/agipdlib.py index 53385959d53d85737ad498cb63b8ad3d856e6213..090ff0b262f0f019feddcaba75ec81b009c57d52 100644 --- a/src/cal_tools/agipdlib.py +++ b/src/cal_tools/agipdlib.py @@ -636,7 +636,6 @@ class AgipdCorrections: :param i_proc: Index of shared memory array to process :param asic: Asic number to process """ - if not self.corr_bools.get("common_mode"): return dark_min = self.cm_dark_min @@ -647,35 +646,13 @@ class AgipdCorrections: if n_img == 0: return cell_id = self.shared_dict[i_proc]['cellId'][:n_img] - row_id = cell_id // 32 data = self.shared_dict[i_proc]['data'][:n_img] data = data.reshape(-1, 8, 64, 2, 64) asic_data = data[:, asic % 8, :, asic // 8, :] - # Loop over rows of cells - for cell_row in range(11): - irow = np.flatnonzero(row_id == cell_row) - if not irow.size: - continue - # Loop over iterations - for _ in range(n_itr): - # Cell common mode - cell_cm_sum, cell_cm_count = \ - calgs.sum_and_count_in_range_cell( - asic_data, irow, dark_min, dark_max) - cell_cm = cell_cm_sum / cell_cm_count - - cell_cm[cell_cm_count < fraction * irow.size] = 0 - asic_data[irow] -= cell_cm[None, :, :] - - # Asics common mode - asic_cm_sum, asic_cm_count = \ - calgs.sum_and_count_in_range_asic( - asic_data, irow, dark_min, dark_max) - asic_cm = asic_cm_sum / asic_cm_count - - asic_cm[asic_cm_count < fraction * 4096] = 0 - asic_data[irow] -= asic_cm[:, None, None] + for _ in range(n_itr): + calgs.cm_correction_1pass( + asic_data, cell_id, dark_min, dark_max, fraction) def mask_zero_std(self, i_proc, cells): """