diff --git a/src/cal_tools/agipdlib.py b/src/cal_tools/agipdlib.py index 88c3413cc623efda893852293865abc2b90db701..3a9da4e2283e9d784def6537b8bda7e8e0163023 100644 --- a/src/cal_tools/agipdlib.py +++ b/src/cal_tools/agipdlib.py @@ -53,12 +53,19 @@ class AgipdCtrl: self.ctrl_src = ctrl_src self.raise_error = raise_error - def get_num_cells(self) -> Optional[int]: - """Read number of memory cells from fast data. + def _get_num_cells_ctrl(self) -> Optional[int]: + """Get number of cells from CONTROL source.""" + # Attempt to look for number of cells in slow data + ncell_src = ( + self.ctrl_src, "bunchStructure.nPulses.value") + if ( + ncell_src[0] in self.run_dc.all_sources and + ncell_src[1] in self.run_dc.keys_for_source(ncell_src[0]) + ): + return int(self.run_dc[ncell_src].as_single_value(reduce_by='max')) - :return mem_cells: Number of memory cells - return None, if no data available. - """ + def _get_num_cells_instr(self) -> Optional[int]: + """Get number of cells from INSTRUMENT source.""" cells = np.squeeze( self.run_dc[ self.image_src, "image.cellId"].drop_empty_trains().ndarray() @@ -70,6 +77,19 @@ class AgipdCtrl: dists = [abs(o - maxcell) for o in options] return options[np.argmin(dists)] + def get_num_cells(self) -> Optional[int]: + """Read number of memory cells from fast data. + + :return mem_cells: Number of memory cells + return None, if no data available. + """ + ncell = self._get_num_cells_ctrl() + if ncell is not None: + return ncell + # In case of data filtering at DAQ, this function produces + # wrong value. + return self._get_num_cells_instr() + def _get_acq_rate_ctrl(self) -> Optional[float]: """Get acquisition (repetition) rate from CONTROL source.""" # Attempt to look for acquisition rate in slow data @@ -83,9 +103,6 @@ class AgipdCtrl: # about bucketing the rate for managing meta-data. return round(float(self.run_dc[rep_rate_src].as_single_value()), 1) - def _get_acq_rate_instr(self) -> Optional[float]: - """Get acquisition (repetition rate) from INSTRUMENT source.""" - def _get_acq_rate_instr(self) -> Optional[float]: """Get acquisition (repetition rate) from INSTRUMENT source.""" @@ -298,7 +315,8 @@ class CellSelection: raise NotImplementedError def get_cells_on_trains( - self, train_sel: np.ndarray, nfrm: np.ndarray, cm: int = 0 + self, train_sel: np.ndarray, nfrm: np.ndarray, + cellid: np.ndarray, cm: int = 0 ) -> np.array: """Returns mask of cells selected for processing @@ -309,6 +327,8 @@ class CellSelection: for common-mode correction :return: boolean array with flags indicating images for processing + :return: integer array with number of frames to use in the second + step in two step selection procedure """ raise NotImplementedError @@ -517,7 +537,7 @@ class AgipdCorrections: n_valid_trains = len(valid_train_ids) data_dict["n_valid_trains"][0] = n_valid_trains data_dict["valid_trains"][:n_valid_trains] = valid_train_ids - data_dict["nimg_in_trains"][:n_valid_trains] = nimg_in_trains + #data_dict["nimg_in_trains"][:n_valid_trains] = nimg_in_trains if "AGIPD500K" in agipd_base: agipd_comp = components.AGIPD500K(im_dc) @@ -532,8 +552,11 @@ class AgipdCorrections: cm = (self.cell_sel.CM_NONE if apply_sel_pulses else self.cell_sel.CM_PRESEL) - img_selected = self.cell_sel.get_cells_on_trains( - np.array(valid_train_ids), nimg_in_trains, cm=cm) + cellid = np.squeeze(im_dc[agipd_base, "image.cellId"].ndarray()) + + img_selected, nimg_in_trains = self.cell_sel.get_cells_on_trains( + np.array(valid_train_ids), nimg_in_trains, cellid, cm=cm) + data_dict["nimg_in_trains"][:n_valid_trains] = nimg_in_trains frm_ix = np.flatnonzero(img_selected) data_dict["cm_presel"][0] = (cm == self.cell_sel.CM_PRESEL) @@ -1004,10 +1027,11 @@ class AgipdCorrections: ntrains = data_dict["n_valid_trains"][0] train_ids = data_dict["valid_trains"][:ntrains] nimg_in_trains = data_dict["nimg_in_trains"][:ntrains] + cellid = data_dict["cellId"][:n_img] # Initializing can_calibrate array - can_calibrate = self.cell_sel.get_cells_on_trains( - train_ids, nimg_in_trains, cm=self.cell_sel.CM_FINSEL + can_calibrate, _ = self.cell_sel.get_cells_on_trains( + train_ids, nimg_in_trains, cellid, cm=self.cell_sel.CM_FINSEL ) if np.all(can_calibrate): return n_img @@ -1606,6 +1630,7 @@ class CellRange(CellSelection): self.flag_cm[:self.max_cells] = self.flag self.flag_cm = (self.flag_cm.reshape(-1, self.row_size).any(1) .repeat(self.row_size)[:self.max_cells]) + self.sel_type = [self.flag, self.flag_cm, self.flag] def msg(self): return ( @@ -1615,10 +1640,24 @@ class CellRange(CellSelection): ) def get_cells_on_trains( - self, train_sel: np.ndarray, nfrm: np.ndarray, cm: int = 0 + self, train_sel: np.ndarray, nfrm: np.ndarray, + cellid: np.ndarray, cm: int = 0 ) -> np.array: - return np.tile(self._sel_for_cm(self.flag, self.flag_cm, cm), - len(train_sel)) + if cm < 0 or cm > 2: + raise ValueError("param 'cm' takes only 0,1,2") + + flag = self.sel_type[cm] + sel = np.zeros(np.sum(nfrm), bool) + counts = np.zeros(len(nfrm), int) + i0 = 0 + for i, nfrm_i in enumerate(nfrm): + iN = i0 + nfrm_i + f = flag[cellid[i0:iN]] + sel[i0:iN] = f + counts[i] = np.sum(f) + i0 = iN + + return sel, counts def filter_trains(self, train_sel: np.ndarray): return train_sel @@ -1695,12 +1734,14 @@ class LitFrameSelection(CellSelection): ) def get_cells_on_trains( - self, train_sel: np.ndarray, nfrm: np.ndarray, cm: int = 0 + self, train_sel: np.ndarray, nfrm: np.ndarray, + cellid: np.ndarray, cm: int = 0 ) -> np.array: cell_flags, cm_flags = self._sel.litframes_on_trains( train_sel, nfrm, [self.final_sel_type, self.cm_sel_type]) - return self._sel_for_cm(cell_flags, cm_flags, cm) + sel = self._sel_for_cm(cell_flags, cm_flags, cm) + return sel, nfrm def filter_trains(self, train_sel: np.ndarray): return self._sel.filter_trains(train_sel, drop_empty=True)