def test_hbins(): print('In pyalgos.test_hbins') from psana.pyalgos.generic.HBins import HBins o = HBins((1, 6), 5) print(' binedges():', o.binedges()) assert (np.array_equal(o.binedges(), np.array((1, 2, 3, 4, 5, 6), dtype=np.float)))
def _set_rad_bins(self, radedges, nradbins): rmin = math.floor(np.amin( self.rad)) if radedges is None else radedges[0] rmax = math.ceil(np.amax( self.rad)) if radedges is None else radedges[-1] if rmin < 1: rmin = 1 self.rb = HBins((rmin, rmax), nradbins)
def test_histogram(): import psana.pyalgos.generic.NDArrGenerators as ag from psana.pyalgos.generic.HBins import HBins nbins = 1000 arr = ag.random_standard((nbins,), mu=50, sigma=10, dtype=ag.np.float64) hb = HBins((0,nbins), nbins=nbins) hb.set_bin_data(arr, dtype=ag.np.float64) return hb
def _set_phi_bins(self, phiedges, nphibins): if phiedges[-1] > phiedges[0]+360\ or phiedges[-1] < phiedges[0]-360: raise ValueError('Difference between angular edges should not exceed 360 degree;'\ ' phiedges: %.0f, %.0f' % (phiedges[0], phiedges[-1])) self.pb = HBins(phiedges, nphibins) phi1, phi2 = self.pb.limits() self.is360 = math.fabs(math.fabs(phi2 - phi1) - 360) < 1e-3
def proc_waveforms(self, wfs, wts) : """ """ # if waveforms are already processed if wfs is self._wfs_old : return self._init_arrays() #print_ndarr(wfs, ' waveforms : ', last=4) assert (self.NUM_CHANNELS==wfs.shape[0]),\ 'expected number of channels in not consistent with waveforms array shape' if self.VERSION == 2 : std = wfs[:,self.IOFFSETBEG:self.IOFFSETEND].std(axis=1) if self.VERSION == 4: self.wfsprep = wfs[:,self.WFBINBEG:self.WFBINEND] else: offsets = wfs[:,self.IOFFSETBEG:self.IOFFSETEND].mean(axis=1) #print(' XXX offsets: %s' % str(offsets)) self.wfsprep = wfs[:,self.WFBINBEG:self.WFBINEND] - offsets.reshape(-1, 1) # subtract wf-offset self.wtsprep = wts[:,self.WFBINBEG:self.WFBINEND] # sec for ch in range(self.NUM_CHANNELS) : wf = self.wfsprep[ch,:] wt = self.wtsprep[ch,:] npeaks = None if self.VERSION == 3 : npeaks, self.wfgi, self.wff, self.wfg, self.thrg, self.edges =\ peak_finder_v3(wf, self.SIGMABINS, self.BASEBINS, self.NSTDTHR, self.GAPBINS, self.DEADBINS,\ self._pkvals[ch,:], self._pkinds[ch,:]) elif self.VERSION == 2 : self.THR = self.NSTDTHR*std[ch] npeaks = peak_finder_v2(wf, self.SIGMABINS, self.THR, self.DEADBINS,\ self._pkvals[ch,:], self._pkinds[ch,:]) elif self.VERSION == 4 : t_list = self.PyCFDs[ch].CFD(wf,wt) npeaks = self._pkinds[ch,:].size if self._pkinds[ch,:].size<=len(t_list) else len(t_list) # need it in V4 to convert _pktsec to _pkinds and _pkvals if self.tbins is None : from psana.pyalgos.generic.HBins import HBins self.tbins = HBins(list(wt)) else : # self.VERSION == 1 npeaks = wfpkfinder_cfd(wf, self.BASE, self.THR, self.CFR, self.DEADTIME, self.LEADINGEDGE,\ self._pkvals[ch,:], self._pkinds[ch,:]) #print(' npeaks:', npeaks) #assert (npeaks<self.NUM_HITS), 'number of found peaks exceeds reserved array shape' if npeaks>=self.NUM_HITS : npeaks = self.NUM_HITS self._number_of_hits[ch] = npeaks if self.VERSION == 4 : self._pktsec[ch, :npeaks] = np.array(t_list)[:npeaks] else: self._pktsec[ch, :npeaks] = wt[self._pkinds[ch, :npeaks]] #sec self._wfs_old = wfs
def set_histogram_from_arr(self, arr, nbins=1000, amin=None, amax=None, frmin=0.001, frmax=0.999, edgemode=0, update_hblimits=True): #if np.array_equal(arr, self.arr_old): return if arr is self.arr_old: return self.arr_old = arr if arr.size<1: return aravel = arr.ravel() vmin, vmax = self.hbins.limits() if self.hbins is not None else (None, None) if self.hbins is None or update_hblimits: vmin = amin if amin is not None else\ aravel.min() if frmin in (0,None) else\ np.quantile(aravel, frmin, axis=0, interpolation='lower') vmax = amax if amax is not None else\ aravel.max() if frmax in (1,None) else\ np.quantile(aravel, frmax, axis=0, interpolation='higher') if not vmin<vmax: vmax=vmin+1 hb = HBins((vmin,vmax), nbins=nbins) hb.set_bin_data_from_array(aravel, dtype=np.float64, edgemode=edgemode) hmin, hmax = 0, hb.bin_data_max() #logger.debug('set_histogram_from_arr %s\n vmin(%.5f%%):%.3f vmax(%.5f%%):%.3f hmin: %.3f hmax: %.3f'%\ # (info_ndarr(aravel, 'arr.ravel'), frmin,vmin,frmax,vmax,hmin,hmax)) hgap = 0.05*(hmax-hmin) rs0 = self.scene().sceneRect() rsy, rsh = (hb.vmin(), hb.vmax()-hb.vmin()) if update_hblimits else (rs0.y(), rs0.height()) rs = QRectF(hmin-hgap, rsy, hmax-hmin+2*hgap, rsh) self.set_rect_scene(rs, set_def=update_hblimits) self.update_my_scene(hbins=hb) self.hbins = hb
def do_work(): prefix = './%s-figs-ti_vs_tj' % gu.str_tstamp( fmt='%Y-%m-%d', time_sec=None) # '%Y-%m-%dT%H:%M:%S%z' gu.create_directory(prefix, mode=0o775) path = os.path.abspath(os.path.dirname(__file__)) print('path to npy flies dir:', path) ti_vs_tj = np.load('%s/ti_vs_tj.npy' % path) t_all = np.load('%s/t_all.npy' % path) trange = (1400., 2900.) print_ndarr(ti_vs_tj, 'ti_vs_tj:\n') print_ndarr(t_all, 't_all:\n') sum_bkg = t_all.sum() sum_cor = ti_vs_tj.sum() print('sum_bkg:', sum_bkg) print('sum_cor:', sum_cor) imrange = trange + trange # (1400., 2900., 1400., 2900.) axim = gr.plotImageLarge(ti_vs_tj, img_range=imrange, amp_range=(0,500), figsize=(11,10),\ title='ti_vs_tj', origin='lower', window=(0.10, 0.08, 0.88, 0.88), cmap='inferno') gr.save('%s/fig-ti_vs_tj.png' % prefix) bkg = np.outer(t_all, t_all) / sum_bkg print_ndarr(bkg, 'bkg:\n') axim = gr.plotImageLarge(bkg, img_range=imrange, amp_range=(0,500), figsize=(11,10),\ title='bkg', origin='lower', window=(0.10, 0.08, 0.88, 0.88), cmap='inferno') gr.save('%s/fig-ti_vs_tj-bkg.png' % prefix) harr = t_all nbins = harr.size ht = HBins(trange, nbins, vtype=np.float32) # ht.binedges() fig, axhi, hi = gr.hist1d(ht.bincenters(), bins=nbins, amp_range=ht.limits(), weights=harr, color='b', show_stat=True,\ log=True, figsize=(7,6), axwin=(0.10, 0.10, 0.88, 0.85), title='1-d bkg',\ xlabel='time of all hits (ns)', ylabel='number of hits', titwin='1-d bkg') gr.save('%s/fig-time-hits.png' % prefix) gr.show()
class WFPeaks : def __init__(self, **kwargs) : """Waveform peak finder wrapper. - wf digitizer channels (0,1,2,3,4) should be ordered for u1,u2,v1,v2[,w1,w2],mcp, respectively """ logger.debug(gu.str_kwargs(kwargs, title='WFPeaks input parameters:')) self.set_wf_peak_finder_parameters(**kwargs) self._wfs_old = None self.tbins = None # need it in V4 to convert _pktsec to _pkinds and _pkvals #---------- def set_wf_peak_finder_parameters(self, **kwargs) : self.NUM_CHANNELS= kwargs.get('numchs', 5) self.NUM_HITS = kwargs.get('numhits',16) self.VERSION = kwargs.get('version', 1) self.DLD = kwargs.get('DLD', False) if True : self.BASE = kwargs.get('cfd_base', 0.) self.THR = kwargs.get('cfd_thr', -0.05) self.CFR = kwargs.get('cfd_cfr', 0.85) self.DEADTIME = kwargs.get('cfd_deadtime', 10.0) self.LEADINGEDGE = kwargs.get('cfd_leadingedge', True) self.IOFFSETBEG = kwargs.get('cfd_ioffsetbeg', 1000) self.IOFFSETEND = kwargs.get('cfd_ioffsetend', 2000) self.WFBINBEG = kwargs.get('cfd_wfbinbeg', 6000) self.WFBINEND = kwargs.get('cfd_wfbinend', 30000) if self.VERSION == 2 : self.SIGMABINS = kwargs.get('pf2_sigmabins', 3) self.NSTDTHR = kwargs.get('pf2_nstdthr', -5) self.DEADBINS = kwargs.get('pf2_deadbins', 10) self.IOFFSETBEG = kwargs.get('pf2_ioffsetbeg', 1000) self.IOFFSETEND = kwargs.get('pf2_ioffsetend', 2000) self.WFBINBEG = kwargs.get('pf2_wfbinbeg', 6000) self.WFBINEND = kwargs.get('pf2_wfbinend', 30000) if self.VERSION == 3 : self.SIGMABINS = kwargs.get('pf3_sigmabins', 3) self.BASEBINS = kwargs.get('pf3_basebins', 100) self.NSTDTHR = kwargs.get('pf3_nstdthr', 5) self.GAPBINS = kwargs.get('pf3_gapbins', 200) self.DEADBINS = kwargs.get('pf3_deadbins', 10) # used in proc_waveforms self.IOFFSETBEG = kwargs.get('pf3_ioffsetbeg', 1000) self.IOFFSETEND = kwargs.get('pf3_ioffsetend', 2000) self.WFBINBEG = kwargs.get('pf3_wfbinbeg', 6000) self.WFBINEND = kwargs.get('pf3_wfbinend', 30000) if self.VERSION == 4 : paramsCFD = kwargs.get('paramsCFD', {}) if self.DLD: self.paramsCFD = {} if self.NUM_CHANNELS == 5: self.cnls = ['x1','x2','y1','y2','mcp'] elif self.NUM_CHANNELS == 7: self.cnls = ['u1','u2','v1','v2','w1','w2','mcp'] if isinstance(paramsCFD,list): for param in paramsCFD: if param['channel'] not in self.cnls: raise NameError("Channel names should be chosen from ['x1','x2','y1','y2','mcp'] for QUAD and ['u1','u2','v1','v2','w1','w2','mcp'] for HEX.") self.paramsCFD[param['channel']] = param elif isinstance(paramsCFD,dict): for k,param in paramsCFD.items(): if param['channel'] not in self.cnls: raise NameError("Channel names should be chosen from ['x1','x2','y1','y2','mcp'] for QUAD and ['u1','u2','v1','v2','w1','w2','mcp'] for HEX.") self.paramsCFD[param['channel']] = param self.PyCFDs = [PyCFD(self.paramsCFD[self.cnls[i]]) for i in range(self.NUM_CHANNELS)] else: if isinstance(paramsCFD,list): self.PyCFDs = [PyCFD(paramsCFD[i]) for i in range(self.NUM_CHANNELS)] elif isinstance(paramsCFD,dict): self.PyCFDs = [PyCFD(param) for k, param in paramsCFD.items()] #---------- def _init_arrays(self) : self._number_of_hits = np.zeros((self.NUM_CHANNELS), dtype=np.int) self._pkvals = np.zeros((self.NUM_CHANNELS,self.NUM_HITS), dtype=np.double) self._pkinds = np.zeros((self.NUM_CHANNELS,self.NUM_HITS), dtype=np.uint32) self._pktsec = np.zeros((self.NUM_CHANNELS,self.NUM_HITS), dtype=np.double) #---------- def proc_waveforms(self, wfs, wts) : """ """ # if waveforms are already processed if wfs is self._wfs_old : return self._init_arrays() #print_ndarr(wfs, ' waveforms : ', last=4) assert (self.NUM_CHANNELS==wfs.shape[0]),\ 'expected number of channels in not consistent with waveforms array shape' if self.VERSION == 2 : std = wfs[:,self.IOFFSETBEG:self.IOFFSETEND].std(axis=1) if self.VERSION == 4: self.wfsprep = wfs[:,self.WFBINBEG:self.WFBINEND] else: offsets = wfs[:,self.IOFFSETBEG:self.IOFFSETEND].mean(axis=1) #print(' XXX offsets: %s' % str(offsets)) self.wfsprep = wfs[:,self.WFBINBEG:self.WFBINEND] - offsets.reshape(-1, 1) # subtract wf-offset self.wtsprep = wts[:,self.WFBINBEG:self.WFBINEND] # sec for ch in range(self.NUM_CHANNELS) : wf = self.wfsprep[ch,:] wt = self.wtsprep[ch,:] npeaks = None if self.VERSION == 3 : npeaks, self.wfgi, self.wff, self.wfg, self.thrg, self.edges =\ peak_finder_v3(wf, self.SIGMABINS, self.BASEBINS, self.NSTDTHR, self.GAPBINS, self.DEADBINS,\ self._pkvals[ch,:], self._pkinds[ch,:]) elif self.VERSION == 2 : self.THR = self.NSTDTHR*std[ch] npeaks = peak_finder_v2(wf, self.SIGMABINS, self.THR, self.DEADBINS,\ self._pkvals[ch,:], self._pkinds[ch,:]) elif self.VERSION == 4 : t_list = self.PyCFDs[ch].CFD(wf,wt) npeaks = self._pkinds[ch,:].size if self._pkinds[ch,:].size<=len(t_list) else len(t_list) # need it in V4 to convert _pktsec to _pkinds and _pkvals if self.tbins is None : from psana.pyalgos.generic.HBins import HBins self.tbins = HBins(list(wt)) else : # self.VERSION == 1 npeaks = wfpkfinder_cfd(wf, self.BASE, self.THR, self.CFR, self.DEADTIME, self.LEADINGEDGE,\ self._pkvals[ch,:], self._pkinds[ch,:]) #print(' npeaks:', npeaks) #assert (npeaks<self.NUM_HITS), 'number of found peaks exceeds reserved array shape' if npeaks>=self.NUM_HITS : npeaks = self.NUM_HITS self._number_of_hits[ch] = npeaks if self.VERSION == 4 : self._pktsec[ch, :npeaks] = np.array(t_list)[:npeaks] else: self._pktsec[ch, :npeaks] = wt[self._pkinds[ch, :npeaks]] #sec self._wfs_old = wfs #---------- def waveforms_preprocessed(self, wfs, wts) : """Returns preprocessed waveforms for selected range [WFBINBEG:WFBINEND]; wfsprep[NUM_CHANNELS,WFBINBEG:WFBINEND] - intensities with subtracted mean evaluated wtsprep[NUM_CHANNELS,WFBINBEG:WFBINEND] - times in [sec] like raw data """ self.proc_waveforms(wfs, wts) return self.wfsprep, self.wtsprep #---------- def number_of_hits(self, wfs, wts) : self.proc_waveforms(wfs, wts) return self._number_of_hits def peak_times_sec(self, wfs, wts) : self.proc_waveforms(wfs, wts) return self._pktsec def peak_indexes(self, wfs, wts) : self.proc_waveforms(wfs, wts) return self._pkinds def peak_values(self, wfs, wts) : self.proc_waveforms(wfs, wts) return self._pkvals def peak_indexes_values(self, wfs, wts) : """ added for V4 to convert _pktsec to _pkinds and _pkvals """ self.proc_waveforms(wfs, wts) if self.VERSION == 4 : # This is SLOW for V4 graphics... for ch in range(self.NUM_CHANNELS) : npeaks = self._number_of_hits[ch] wf = self.wfsprep[ch,:] self._pkinds[ch, :npeaks] = self.tbins.bin_indexes(self._pktsec[ch, :npeaks]) self._pkvals[ch, :npeaks] = wf[self._pkinds[ch, :npeaks]] return self._pkinds, self._pkvals def __call__(self, wfs, wts) : self.proc_waveforms(wfs, wts) return self._number_of_hits,\ self._pkinds,\ self._pkvals,\ self._pktsec #---------- def __del__(self) : pass
def __init__(self, proc, **kwargs): self.proc = proc logger.info('In set_parameters, **kwargs: %s' % str(kwargs)) self.STAT_NHITS = kwargs.get('STAT_NHITS', True) self.STAT_TIME_CH = kwargs.get('STAT_TIME_CH', True) self.STAT_UVW = kwargs.get('STAT_UVW', True) self.STAT_TIME_SUMS = kwargs.get('STAT_TIME_SUMS', True) self.STAT_CORRELATIONS = kwargs.get('STAT_CORRELATIONS', True) self.STAT_XY_COMPONENTS = kwargs.get('STAT_XY_COMPONENTS', True) self.STAT_XY_2D = kwargs.get('STAT_XY_2D', True) self.STAT_MISC = kwargs.get('STAT_MISC', True) self.STAT_REFLECTIONS = kwargs.get('STAT_REFLECTIONS', True) self.STAT_PHYSICS = kwargs.get('STAT_PHYSICS', True) self.STAT_XY_RESOLUTION = kwargs.get('STAT_XY_RESOLUTION', False) # not available for QUAD if self.STAT_TIME_CH: self.lst_u1 = [] self.lst_u2 = [] self.lst_v1 = [] self.lst_v2 = [] self.lst_w1 = [] self.lst_w2 = [] self.lst_mcp = [] if self.STAT_NHITS: self.lst_nhits_u1 = [] self.lst_nhits_u2 = [] self.lst_nhits_v1 = [] self.lst_nhits_v2 = [] self.lst_nhits_w1 = [] self.lst_nhits_w2 = [] self.lst_nhits_mcp = [] self.lst_nparts = [] if self.STAT_UVW or self.STAT_CORRELATIONS: self.lst_u_ns = [] self.lst_v_ns = [] self.lst_w_ns = [] self.lst_u = [] self.lst_v = [] self.lst_w = [] if self.STAT_TIME_SUMS or self.STAT_CORRELATIONS: self.lst_time_sum_u = [] self.lst_time_sum_v = [] self.lst_time_sum_w = [] self.lst_time_sum_u_corr = [] self.lst_time_sum_v_corr = [] self.lst_time_sum_w_corr = [] if self.STAT_XY_COMPONENTS: self.lst_Xuv = [] self.lst_Xuw = [] self.lst_Xvw = [] self.lst_Yuv = [] self.lst_Yuw = [] self.lst_Yvw = [] if self.STAT_MISC: self.list_dr = [] self.lst_consist_indicator = [] self.lst_rec_method = [] if self.STAT_XY_RESOLUTION: self.lst_binx = [] self.lst_biny = [] self.lst_resol_fwhm = [] if self.STAT_REFLECTIONS: self.lst_refl_u1 = [] self.lst_refl_u2 = [] self.lst_refl_v1 = [] self.lst_refl_v2 = [] self.lst_refl_w1 = [] self.lst_refl_w2 = [] if self.STAT_XY_2D: # images nbins = 360 self.img_x_bins = HBins((-45., 45.), nbins, vtype=np.float32) self.img_y_bins = HBins((-45., 45.), nbins, vtype=np.float32) self.img_xy_uv = np.zeros((nbins, nbins), dtype=np.float32) self.img_xy_uw = np.zeros((nbins, nbins), dtype=np.float32) self.img_xy_vw = np.zeros((nbins, nbins), dtype=np.float32) self.img_xy_1 = np.zeros((nbins, nbins), dtype=np.float32) self.img_xy_2 = np.zeros((nbins, nbins), dtype=np.float32) if self.STAT_PHYSICS: t_ns_nbins = 300 self.t_ns_bins = HBins((1400., 2900.), t_ns_nbins, vtype=np.float32) #self.t1_vs_t0 = np.zeros((t_ns_nbins, t_ns_nbins), dtype=np.float32) self.ti_vs_tj = np.zeros((t_ns_nbins, t_ns_nbins), dtype=np.float32) self.t_all = np.zeros((t_ns_nbins, ), dtype=np.float32) self.lst_t_all = [] x_mm_nbins = 200 y_mm_nbins = 200 r_mm_nbins = 200 self.x_mm_bins = HBins((-50., 50.), x_mm_nbins, vtype=np.float32) self.y_mm_bins = HBins((-50., 50.), y_mm_nbins, vtype=np.float32) self.r_mm_bins = HBins((-50., 50.), r_mm_nbins, vtype=np.float32) #self.x_vs_t0 = np.zeros((x_mm_nbins, t_ns_nbins), dtype=np.float32) #self.y_vs_t0 = np.zeros((y_mm_nbins, t_ns_nbins), dtype=np.float32) self.rsx_vs_t = np.zeros((r_mm_nbins, t_ns_nbins), dtype=np.float32) self.rsy_vs_t = np.zeros((r_mm_nbins, t_ns_nbins), dtype=np.float32)
class DLDStatistics: """ holds, fills, and provide access to statistical arrays for MCP DLD data processing """ def __init__(self, proc, **kwargs): self.proc = proc logger.info('In set_parameters, **kwargs: %s' % str(kwargs)) self.STAT_NHITS = kwargs.get('STAT_NHITS', True) self.STAT_TIME_CH = kwargs.get('STAT_TIME_CH', True) self.STAT_UVW = kwargs.get('STAT_UVW', True) self.STAT_TIME_SUMS = kwargs.get('STAT_TIME_SUMS', True) self.STAT_CORRELATIONS = kwargs.get('STAT_CORRELATIONS', True) self.STAT_XY_COMPONENTS = kwargs.get('STAT_XY_COMPONENTS', True) self.STAT_XY_2D = kwargs.get('STAT_XY_2D', True) self.STAT_MISC = kwargs.get('STAT_MISC', True) self.STAT_REFLECTIONS = kwargs.get('STAT_REFLECTIONS', True) self.STAT_PHYSICS = kwargs.get('STAT_PHYSICS', True) self.STAT_XY_RESOLUTION = kwargs.get('STAT_XY_RESOLUTION', False) # not available for QUAD if self.STAT_TIME_CH: self.lst_u1 = [] self.lst_u2 = [] self.lst_v1 = [] self.lst_v2 = [] self.lst_w1 = [] self.lst_w2 = [] self.lst_mcp = [] if self.STAT_NHITS: self.lst_nhits_u1 = [] self.lst_nhits_u2 = [] self.lst_nhits_v1 = [] self.lst_nhits_v2 = [] self.lst_nhits_w1 = [] self.lst_nhits_w2 = [] self.lst_nhits_mcp = [] self.lst_nparts = [] if self.STAT_UVW or self.STAT_CORRELATIONS: self.lst_u_ns = [] self.lst_v_ns = [] self.lst_w_ns = [] self.lst_u = [] self.lst_v = [] self.lst_w = [] if self.STAT_TIME_SUMS or self.STAT_CORRELATIONS: self.lst_time_sum_u = [] self.lst_time_sum_v = [] self.lst_time_sum_w = [] self.lst_time_sum_u_corr = [] self.lst_time_sum_v_corr = [] self.lst_time_sum_w_corr = [] if self.STAT_XY_COMPONENTS: self.lst_Xuv = [] self.lst_Xuw = [] self.lst_Xvw = [] self.lst_Yuv = [] self.lst_Yuw = [] self.lst_Yvw = [] if self.STAT_MISC: self.list_dr = [] self.lst_consist_indicator = [] self.lst_rec_method = [] if self.STAT_XY_RESOLUTION: self.lst_binx = [] self.lst_biny = [] self.lst_resol_fwhm = [] if self.STAT_REFLECTIONS: self.lst_refl_u1 = [] self.lst_refl_u2 = [] self.lst_refl_v1 = [] self.lst_refl_v2 = [] self.lst_refl_w1 = [] self.lst_refl_w2 = [] if self.STAT_XY_2D: # images nbins = 360 self.img_x_bins = HBins((-45., 45.), nbins, vtype=np.float32) self.img_y_bins = HBins((-45., 45.), nbins, vtype=np.float32) self.img_xy_uv = np.zeros((nbins, nbins), dtype=np.float32) self.img_xy_uw = np.zeros((nbins, nbins), dtype=np.float32) self.img_xy_vw = np.zeros((nbins, nbins), dtype=np.float32) self.img_xy_1 = np.zeros((nbins, nbins), dtype=np.float32) self.img_xy_2 = np.zeros((nbins, nbins), dtype=np.float32) if self.STAT_PHYSICS: t_ns_nbins = 300 self.t_ns_bins = HBins((1400., 2900.), t_ns_nbins, vtype=np.float32) #self.t1_vs_t0 = np.zeros((t_ns_nbins, t_ns_nbins), dtype=np.float32) self.ti_vs_tj = np.zeros((t_ns_nbins, t_ns_nbins), dtype=np.float32) self.t_all = np.zeros((t_ns_nbins, ), dtype=np.float32) self.lst_t_all = [] x_mm_nbins = 200 y_mm_nbins = 200 r_mm_nbins = 200 self.x_mm_bins = HBins((-50., 50.), x_mm_nbins, vtype=np.float32) self.y_mm_bins = HBins((-50., 50.), y_mm_nbins, vtype=np.float32) self.r_mm_bins = HBins((-50., 50.), r_mm_nbins, vtype=np.float32) #self.x_vs_t0 = np.zeros((x_mm_nbins, t_ns_nbins), dtype=np.float32) #self.y_vs_t0 = np.zeros((y_mm_nbins, t_ns_nbins), dtype=np.float32) self.rsx_vs_t = np.zeros((r_mm_nbins, t_ns_nbins), dtype=np.float32) self.rsy_vs_t = np.zeros((r_mm_nbins, t_ns_nbins), dtype=np.float32) #---------- def fill_data(self, number_of_hits, tdc_sec): if self.fill_corrected_data(): self.fill_raw_data(number_of_hits, tdc_sec) #---------- def fill_raw_data(self, number_of_hits, tdc_sec): tdc_ns = tdc_sec * SEC_TO_NS # sec -> ns sorter = self.proc.sorter Cu1, Cu2, Cv1, Cv2, Cw1, Cw2, Cmcp = sorter.channel_indexes if self.STAT_NHITS: self.lst_nhits_mcp.append(number_of_hits[Cmcp]) self.lst_nhits_u1.append(number_of_hits[Cu1]) self.lst_nhits_u2.append(number_of_hits[Cu2]) self.lst_nhits_v1.append(number_of_hits[Cv1]) self.lst_nhits_v2.append(number_of_hits[Cv2]) if sorter.use_hex: self.lst_nhits_w1.append(number_of_hits[Cw1]) self.lst_nhits_w2.append(number_of_hits[Cw2]) if self.STAT_TIME_CH: self.lst_mcp.append(tdc_ns[Cmcp, 0]) self.lst_u1.append(tdc_ns[Cu1, 0]) self.lst_u2.append(tdc_ns[Cu2, 0]) self.lst_v1.append(tdc_ns[Cv1, 0]) self.lst_v2.append(tdc_ns[Cv2, 0]) if sorter.use_hex: self.lst_w1.append(tdc_ns[Cw1, 0]) self.lst_w2.append(tdc_ns[Cw2, 0]) if self.STAT_REFLECTIONS: if number_of_hits[Cu2] > 1: self.lst_refl_u1.append(tdc_ns[Cu2, 1] - tdc_ns[Cu1, 0]) if number_of_hits[Cu1] > 1: self.lst_refl_u2.append(tdc_ns[Cu1, 1] - tdc_ns[Cu2, 0]) if number_of_hits[Cv2] > 1: self.lst_refl_v1.append(tdc_ns[Cv2, 1] - tdc_ns[Cv1, 0]) if number_of_hits[Cv1] > 1: self.lst_refl_v2.append(tdc_ns[Cv1, 1] - tdc_ns[Cv2, 0]) if sorter.use_hex: if number_of_hits[Cw2] > 1: self.lst_refl_w1.append(tdc_ns[Cw2, 1] - tdc_ns[Cw1, 0]) if number_of_hits[Cw1] > 1: self.lst_refl_w2.append(tdc_ns[Cw1, 1] - tdc_ns[Cw2, 0]) time_sum_u = tdc_ns[Cu1, 0] + tdc_ns[Cu2, 0] - 2 * tdc_ns[Cmcp, 0] time_sum_v = tdc_ns[Cv1, 0] + tdc_ns[Cv2, 0] - 2 * tdc_ns[Cmcp, 0] time_sum_w = tdc_ns[Cw1, 0] + tdc_ns[ Cw2, 0] - 2 * tdc_ns[Cmcp, 0] if sorter.use_hex else 0 #logger.info("RAW time_sum_u: %.2f _v: %.2f _w: %.2f " % (time_sum_u, time_sum_v, time_sum_w)) if self.STAT_TIME_SUMS or self.STAT_CORRELATIONS: self.lst_time_sum_u.append(time_sum_u) self.lst_time_sum_v.append(time_sum_v) if sorter.use_hex: self.lst_time_sum_w.append(time_sum_w) #if self.STAT_XY_RESOLUTION : # NOT VALID FOR QUAD #sfco = hexanode.py_scalefactors_calibration_class(sorter) # NOT FOR QUAD # #logger.info(" binx: %d biny: %d resolution(FWHM): %.6f" % (sfco.binx, sfco.biny, sfco.detector_map_resol_FWHM_fill)) # if sfco.binx>=0 and sfco.biny>=0 : # self.lst_binx.append(sfco.binx) # self.lst_biny.append(sfco.biny) # self.lst_resol_fwhm.append(sfco.detector_map_resol_FWHM_fill) #---------- def fill_corrected_data(self): sorter = self.proc.sorter Cu1, Cu2, Cv1, Cv2, Cw1, Cw2, Cmcp = sorter.channel_indexes number_of_particles = sorter.output_number_of_hits if self.STAT_NHITS: self.lst_nparts.append(number_of_particles) # Discards most of events in command>1 #===================== if number_of_particles < 1: logger.debug('no hits found in event ') return False #===================== tdc_ns = self.proc.tdc_ns u_ns = tdc_ns[Cu1, 0] - tdc_ns[Cu2, 0] v_ns = tdc_ns[Cv1, 0] - tdc_ns[Cv2, 0] w_ns = 0 #tdc_ns[Cw1,0] - tdc_ns[Cw2,0] u = u_ns * sorter.fu v = v_ns * sorter.fv w = 0 #(w_ns + self.w_offset) * sorter.fw Xuv = u Xuw = 0 #u Xvw = 0 #v + w Yuv = v #(u - 2*v)*OSQRT3 Yuw = 0 #(2*w - u)*OSQRT3 Yvw = 0 # (w - v)*OSQRT3 dX = 0 # Xuv - Xvw dY = 0 # Yuv - Yvw time_sum_u_corr = tdc_ns[Cu1, 0] + tdc_ns[Cu2, 0] - 2 * tdc_ns[Cmcp, 0] time_sum_v_corr = tdc_ns[Cv1, 0] + tdc_ns[Cv2, 0] - 2 * tdc_ns[Cmcp, 0] time_sum_w_corr = 0 # tdc_ns[Cw1,0] + tdc_ns[Cw2,0] - 2*tdc_ns[Cmcp,0] if sorter.use_hex: w_ns = tdc_ns[Cw1, 0] - tdc_ns[Cw2, 0] w = (w_ns + self.w_offset) * sorter.fw Xuw = u Xvw = v + w Yuv = (u - 2 * v) * OSQRT3 Yuw = (2 * w - u) * OSQRT3 Yvw = (w - v) * OSQRT3 dX = Xuv - Xvw dY = Yuv - Yvw time_sum_w_corr = tdc_ns[Cw1, 0] + tdc_ns[Cw2, 0] - 2 * tdc_ns[Cmcp, 0] #--------- if self.STAT_UVW or self.STAT_CORRELATIONS: self.lst_u_ns.append(u_ns) self.lst_v_ns.append(v_ns) self.lst_w_ns.append(w_ns) self.lst_u.append(u) self.lst_v.append(v) self.lst_w.append(w) if self.STAT_TIME_SUMS or self.STAT_CORRELATIONS: self.lst_time_sum_u_corr.append(time_sum_u_corr) self.lst_time_sum_v_corr.append(time_sum_v_corr) self.lst_time_sum_w_corr.append(time_sum_w_corr) if self.STAT_XY_COMPONENTS: self.lst_Xuv.append(Xuv) self.lst_Xuw.append(Xuw) self.lst_Xvw.append(Xvw) self.lst_Yuv.append(Yuv) self.lst_Yuw.append(Yuw) self.lst_Yvw.append(Yvw) hco = py_hit_class(sorter, 0) if self.STAT_MISC: inds_incr = ((Cu1,1), (Cu2,2), (Cv1,4), (Cv2,8), (Cw1,16), (Cw2,32), (Cmcp,64)) if sorter.use_hex else\ ((Cu1,1), (Cu2,2), (Cv1,4), (Cv2,8), (Cmcp,16)) dR = sqrt(dX * dX + dY * dY) self.list_dr.append(dR) # fill Consistence Indicator consistenceIndicator = 0 for (ind, incr) in inds_incr: if self.proc.number_of_hits[ind] > 0: consistenceIndicator += incr self.lst_consist_indicator.append(consistenceIndicator) self.lst_rec_method.append(hco.method) #logger.info('reconstruction method %d' % hco.method) if self.STAT_XY_2D: # fill 2-d images x1, y1 = hco.x, hco.y x2, y2 = (-10, -10) if number_of_particles > 1: hco2 = py_hit_class(sorter, 1) x2, y2 = hco2.x, hco2.y ix1, ix2, ixuv, ixuw, ixvw = self.img_x_bins.bin_indexes( (x1, x2, Xuv, Xuw, Xvw)) iy1, iy2, iyuv, iyuw, iyvw = self.img_y_bins.bin_indexes( (y1, y2, Yuv, Yuw, Yvw)) self.img_xy_1[iy1, ix1] += 1 self.img_xy_2[iy2, ix2] += 1 self.img_xy_uv[iyuv, ixuv] += 1 self.img_xy_uw[iyuw, ixuw] += 1 self.img_xy_vw[iyvw, ixvw] += 1 if self.STAT_PHYSICS: if self.proc.number_of_hits[Cmcp] > 1: #t0, t1 = tdc_ns[Cmcp,:2] #it0, it1 = self.t_ns_bins.bin_indexes((t0, t1)) #self.t1_vs_t0[it1, it0] += 1 #ix, iy = self.x_mm_bins.bin_indexes((Xuv,Yuv)) #self.x_vs_t0[ix, it0] += 1 #self.y_vs_t0[iy, it0] += 1 #logger.info(" Event %5i number_of_particles: %i" % (evnum, number_of_particles)) #for i in range(number_of_particles) : # hco = py_hit_class(sorter, i) # #logger.info(" p:%2i x:%7.3f y:%7.3f t:%7.3f met:%d" % (i, hco.x, hco.y, hco.time, hco.method)) # x,y,t = hco.x, hco.y, hco.time # r = sqrt(x*x+y*y) # if x<0 : r=-r # ir = self.r_mm_bins.bin_indexes((r,)) # it = self.t_ns_bins.bin_indexes((t,)) # self.r_vs_t[ir, it] += 1 for x, y, r, t in sorter.xyrt_list(): #irx, iry = self.r_mm_bins.bin_indexes((r if x>0 else -r, r if y>0 else -r)) iry = self.r_mm_bins.bin_indexes((r if y > 0 else -r, )) it = self.t_ns_bins.bin_indexes((t * SEC_TO_NS, )) #self.rsx_vs_t[irx, it] += 1 self.rsy_vs_t[iry, it] += 1 times = np.array(sorter.t_list()) * SEC_TO_NS tinds = self.t_ns_bins.bin_indexes( times) # INDEXES SHOULD BE np.array #print_ndarr(times, '\n XXX times') #print_ndarr(tinds, '\n XXX tinds') # accumulate times in the list for t in times: self.lst_t_all.append(t) # accumulate times directly in histogram to evaluate average self.t_all[tinds] += 1 # accumulate times in correlation matrix for i in tinds: self.ti_vs_tj[i, tinds] += 1 return True
class HPolar(): def __init__(self, xarr, yarr, mask=None, radedges=None, nradbins=100, phiedges=(0, 360), nphibins=32): """Parameters - mask - n-d array with mask - xarr - n-d array with pixel x coordinates in any units - yarr - n-d array with pixel y coordinates in the same units as xarr - radedges - radial bin edges for corrected region in the same units of xarr; default=None - all radial range - nradbins - number of radial bins - phiedges - phi angle bin edges for corrected region. default=(0,360) Difference of the edge limits should not exceed +/-360 degree - nphibins - number of angular bins default=32 - bin size equal to 1 rhumb for default phiedges """ self.rad, self.phi0 = cart2polar(xarr, yarr) self.shapeflat = (self.rad.size, ) self.rad.shape = self.shapeflat self.phi0.shape = self.shapeflat self.mask = mask phimin = min(phiedges[0], phiedges[-1]) self.phi = np.select((self.phi0 < phimin, self.phi0 >= phimin), (self.phi0 + 360., self.phi0)) self._set_rad_bins(radedges, nradbins) self._set_phi_bins(phiedges, nphibins) npbins = self.pb.nbins() nrbins = self.rb.nbins() self.ntbins = npbins * nrbins # total number of bins in r-phi array self.irad = self.rb.bin_indexes(self.rad, edgemode=1) self.iphi = self.pb.bin_indexes(self.phi, edgemode=1) self.cond = np.logical_and(\ np.logical_and(self.irad > -1, self.irad < nrbins), np.logical_and(self.iphi > -1, self.iphi < npbins) ) if mask is not None: self.cond = np.logical_and(self.cond, mask.astype(np.bool).ravel()) # index ntbins stands for overflow bin self.iseq = np.select((self.cond, ), (self.iphi * nrbins + self.irad, ), self.ntbins).ravel() #self.npix_per_bin = np.bincount(self.iseq, weights=None, minlength=None) self.npix_per_bin = np.bincount(self.iseq, weights=None, minlength=self.ntbins + 1) self.griddata = None def _set_rad_bins(self, radedges, nradbins): rmin = math.floor(np.amin( self.rad)) if radedges is None else radedges[0] rmax = math.ceil(np.amax( self.rad)) if radedges is None else radedges[-1] if rmin < 1: rmin = 1 self.rb = HBins((rmin, rmax), nradbins) def _set_phi_bins(self, phiedges, nphibins): if phiedges[-1] > phiedges[0]+360\ or phiedges[-1] < phiedges[0]-360: raise ValueError('Difference between angular edges should not exceed 360 degree;'\ ' phiedges: %.0f, %.0f' % (phiedges[0], phiedges[-1])) self.pb = HBins(phiedges, nphibins) phi1, phi2 = self.pb.limits() self.is360 = math.fabs(math.fabs(phi2 - phi1) - 360) < 1e-3 def info_attrs(self): return '%s attrbutes:' % self.__class__.__name__\ + self.pb.strrange(fmt='\nPhi bins: min:%8.1f max:%8.1f nbins:%5d')\ + self.rb.strrange(fmt='\nRad bins: min:%8.1f max:%8.1f nbins:%5d') def print_attrs(self): print(self.info_attrs()) def print_ndarrs(self): print('%s n-d arrays:' % self.__class__.__name__) print_ndarr(self.rad, ' rad') print_ndarr(self.phi, ' phi') print_ndarr(self.mask, ' mask') #print('Phi limits: ', phiedges[0], phiedges[-1]) def obj_radbins(self): """Returns HBins object for radial bins.""" return self.rb def obj_phibins(self): """Returns HBins object for angular bins.""" return self.pb def pixel_rad(self): """Returns 1-d numpy array of pixel radial parameters.""" return self.rad def pixel_irad(self): """Returns 1-d numpy array of pixel radial indexes [-1,nrbins] - extended edgemode.""" return self.irad def pixel_phi0(self): """Returns 1-d numpy array of pixel angules in the range [-180,180] degree.""" return self.phi0 def pixel_phi(self): """Returns 1-d numpy array of pixel angules in the range [phi_min, phi_min+360] degree.""" return self.phi def pixel_iphi(self): """Returns 1-d numpy array of pixel angular indexes [-1,npbins] - extended edgemode.""" return self.iphi def pixel_iseq(self): """Returns 1-d numpy array of sequentially (in rad and phi) numerated pixel indexes [0,ntbins]. WARNING: pixels outside the r-phi region of interest marked by the index ntbins, ntbins - total number of r-phi bins, which exceeds allowed range of r-phi indices... """ return self.iseq def bin_number_of_pixels(self): """Returns 1-d numpy array of number of accounted pixels per bin.""" return self.npix_per_bin def _ravel_(self, nda): if len(nda.shape) > 1: #nda.shape = self.shapeflat return nda.ravel( ) # return ravel copy in order to preserve input array shape return nda def bin_intensity(self, nda): """Returns 1-d numpy array of total pixel intensity per bin for input array nda.""" #return np.bincount(self.iseq, weights=self._ravel_(nda), minlength=None) return np.bincount(self.iseq, weights=self._ravel_(nda), minlength=self.ntbins + 1) # +1 for overflow bin def bin_avrg(self, nda): """Returns 1-d numpy array of averaged in r-phi bin intensities for input image array nda. WARNING array range [0, nrbins*npbins + 1], where +1 bin intensity is for all off ROI pixels. """ num = self.bin_intensity(self._ravel_(nda)) den = self.bin_number_of_pixels() #print_ndarr(nda, name='ZZZ bin_avrg: nda', first=0, last=5) #print_ndarr(num, name='ZZZ bin_avrg: num', first=0, last=5) #print_ndarr(den, name='ZZZ bin_avrg: den', first=0, last=5) return divide_protected(num, den, vsub_zero=0) def bin_avrg_rad_phi(self, nda, do_transp=True): """Returns 2-d (rad,phi) numpy array of averaged in bin intensity for input array nda.""" arr_rphi = self.bin_avrg( self._ravel_(nda))[:-1] # -1 removes off ROI bin arr_rphi.shape = (self.pb.nbins(), self.rb.nbins()) return np.transpose(arr_rphi) if do_transp else arr_rphi def pixel_avrg(self, nda, subs_value=0): """Makes r-phi histogram of intensities from input image array and projects r-phi averaged intensities back to image. Returns ravel 1-d numpy array of per-pixel intensities taken from r-phi histogram. - nda - input (2-d or 1-d-ravel) pixel array. - subs_value - value sabstituted for pixels out of ROI defined by the min/max in r-phi. """ bin_avrg = self.bin_avrg(self._ravel_(nda)) return np.select((self.cond, ), (bin_avrg[self.iseq], ), subs_value).ravel() #return np.array([bin_avrg[i] for i in self.iseq]) # iseq may be outside the bin_avrg range def pixel_avrg_interpol(self, nda, method='linear', verb=False, subs_value=0): # 'nearest' 'cubic' """Makes r-phi histogram of intensities from input image and projects r-phi averaged intensities back to image with per-pixel interpolation. Returns 1-d numpy array of per-pixel interpolated intensities taken from r-phi histogram. - subs_value - value sabstituted for pixels out of ROI defined by the min/max in r-phi. """ #if not is360: raise ValueError('Interpolation works for 360 degree coverage ONLY') if self.griddata is None: from scipy.interpolate import griddata self.griddata = griddata # 1) get values in bin centers binv = self.bin_avrg_rad_phi(self._ravel_(nda), do_transp=False) # 2) add values in bin edges if verb: print('binv.shape: ', binv.shape) vrad_a1, vrad_a2 = binv[0, :], binv[-1, :] if self.is360: vrad_a1 = vrad_a2 = 0.5 * (binv[0, :] + binv[-1, :] ) # [iphi, irad] nodea = np.vstack((vrad_a1, binv, vrad_a2)) vang_rmin, vang_rmax = nodea[:, 0], nodea[:, -1] vang_rmin.shape = vang_rmax.shape = (vang_rmin.size, 1 ) # it should be 2d for hstack val_nodes = np.hstack((vang_rmin, nodea, vang_rmax)) if verb: print('nodear.shape: ', val_nodes.shape) # 3) extend bin-centers by limits bcentsr = self.rb.bincenters() bcentsp = self.pb.bincenters() blimsr = self.rb.limits() blimsp = self.pb.limits() rad_nodes = np.concatenate(((blimsr[0], ), bcentsr, (blimsr[1], ))) phi_nodes = np.concatenate(((blimsp[0], ), bcentsp, (blimsp[1], ))) if verb: print('rad_nodes.shape', rad_nodes.shape) if verb: print('phi_nodes.shape', phi_nodes.shape) # 4) make point coordinate and value arrays points_rad, points_phi = np.meshgrid(rad_nodes, phi_nodes) if verb: print('points_phi.shape', points_phi.shape) if verb: print('points_rad.shape', points_rad.shape) points = np.vstack((points_phi.ravel(), points_rad.ravel())).T values = val_nodes.ravel() if verb: #print('points:', points) print('points.shape', points.shape) print('values.shape', values.shape) # 5) return interpolated data on (phi, rad) grid grid_vals = self.griddata(points, values, (self.phi, self.rad), method=method) return np.select((self.iseq < self.ntbins, ), (grid_vals, ), default=subs_value)
def __init__(self): # set default parameters self.set_parameters() if self.PLOT_TIME_CH: self.lst_u1 = [] self.lst_u2 = [] self.lst_v1 = [] self.lst_v2 = [] self.lst_w1 = [] self.lst_w2 = [] self.lst_mcp = [] if self.PLOT_NHITS: self.lst_nhits_u1 = [] self.lst_nhits_u2 = [] self.lst_nhits_v1 = [] self.lst_nhits_v2 = [] self.lst_nhits_w1 = [] self.lst_nhits_w2 = [] self.lst_nhits_mcp = [] self.lst_nparts = [] if self.PLOT_UVW or self.PLOT_CORRELATIONS: self.lst_u_ns = [] self.lst_v_ns = [] self.lst_w_ns = [] self.lst_u = [] self.lst_v = [] self.lst_w = [] if self.PLOT_TIME_SUMS or self.PLOT_CORRELATIONS: self.lst_time_sum_u = [] self.lst_time_sum_v = [] self.lst_time_sum_w = [] self.lst_time_sum_u_corr = [] self.lst_time_sum_v_corr = [] self.lst_time_sum_w_corr = [] if self.PLOT_XY_COMPONENTS: self.lst_Xuv = [] self.lst_Xuw = [] self.lst_Xvw = [] self.lst_Yuv = [] self.lst_Yuw = [] self.lst_Yvw = [] if self.PLOT_MISC: self.list_dr = [] self.lst_consist_indicator = [] self.lst_rec_method = [] #if self.PLOT_XY_RESOLUTION : # self.lst_binx = [] # self.lst_biny = [] # self.lst_resol_fwhm = [] if self.PLOT_REFLECTIONS: self.lst_refl_u1 = [] self.lst_refl_u2 = [] self.lst_refl_v1 = [] self.lst_refl_v2 = [] self.lst_refl_w1 = [] self.lst_refl_w2 = [] if self.PLOT_XY_2D: # images nbins = 360 self.img_x_bins = HBins((-45., 45.), nbins, vtype=np.float32) self.img_y_bins = HBins((-45., 45.), nbins, vtype=np.float32) self.img_xy_uv = np.zeros((nbins, nbins), dtype=np.float32) self.img_xy_uw = np.zeros((nbins, nbins), dtype=np.float32) self.img_xy_vw = np.zeros((nbins, nbins), dtype=np.float32) self.img_xy_1 = np.zeros((nbins, nbins), dtype=np.float32) self.img_xy_2 = np.zeros((nbins, nbins), dtype=np.float32) if self.PLOT_PHYSICS: t_ns_nbins = 300 self.t_ns_bins = HBins((1400., 2900.), t_ns_nbins, vtype=np.float32) #self.t1_vs_t0 = np.zeros((t_ns_nbins, t_ns_nbins), dtype=np.float32) self.ti_vs_tj = np.zeros((t_ns_nbins, t_ns_nbins), dtype=np.float32) self.t_all = np.zeros((t_ns_nbins, ), dtype=np.float32) self.lst_t_all = [] x_mm_nbins = 200 y_mm_nbins = 200 r_mm_nbins = 200 self.x_mm_bins = HBins((-50., 50.), x_mm_nbins, vtype=np.float32) self.y_mm_bins = HBins((-50., 50.), y_mm_nbins, vtype=np.float32) self.r_mm_bins = HBins((-50., 50.), r_mm_nbins, vtype=np.float32) #self.x_vs_t0 = np.zeros((x_mm_nbins, t_ns_nbins), dtype=np.float32) #self.y_vs_t0 = np.zeros((y_mm_nbins, t_ns_nbins), dtype=np.float32) self.rsx_vs_t = np.zeros((r_mm_nbins, t_ns_nbins), dtype=np.float32) self.rsy_vs_t = np.zeros((r_mm_nbins, t_ns_nbins), dtype=np.float32)
class HPolar(): def __init__(self, xarr, yarr, mask=None, radedges=None, nradbins=100, phiedges=(0, 360), nphibins=32): """Parameters - mask - n-d array with mask - xarr - n-d array with pixel x coordinates in any units - yarr - n-d array with pixel y coordinates in the same units as xarr - radedges - radial bin edges for corrected region in the same units of xarr; default=None - all radial range - nradbins - number of radial bins - phiedges - phi ange bin edges for corrected region. default=(0,360) Difference of the edge limits should not exceed +/-360 degree - nphibins - number of angular bins default=32 - bin size equal to 1 rhumb for default phiedges """ self.rad, self.phi0 = cart2polar(xarr, yarr) self.shapeflat = (self.rad.size, ) self.rad.shape = self.shapeflat self.phi0.shape = self.shapeflat self.mask = mask phimin = min(phiedges[0], phiedges[-1]) self.phi = np.select((self.phi0 < phimin, self.phi0 >= phimin), (self.phi0 + 360., self.phi0)) self._set_rad_bins(radedges, nradbins) self._set_phi_bins(phiedges, nphibins) npbins = self.pb.nbins() nrbins = self.rb.nbins() ntbins = npbins * nrbins self.irad = self.rb.bin_indexes(self.rad, edgemode=1) self.iphi = self.pb.bin_indexes(self.phi, edgemode=1) cond = np.logical_and(\ np.logical_and(self.irad > -1, self.irad < nrbins), np.logical_and(self.iphi > -1, self.iphi < npbins) ) if mask is not None: cond = np.logical_and(cond, mask.astype(np.bool).flatten()) self.iseq = np.select((cond, ), (self.iphi * nrbins + self.irad, ), ntbins).flatten() self.npix_per_bin = np.bincount(self.iseq, weights=None, minlength=None) self.griddata = None self.print_ndarr = None def _set_rad_bins(self, radedges, nradbins): rmin = math.floor(np.amin( self.rad)) if radedges is None else radedges[0] rmax = math.ceil(np.amax( self.rad)) if radedges is None else radedges[-1] if rmin < 1: rmin = 1 self.rb = HBins((rmin, rmax), nradbins) def _set_phi_bins(self, phiedges, nphibins): if phiedges[-1] > phiedges[0]+360\ or phiedges[-1] < phiedges[0]-360: raise ValueError('Difference between angular edges should not exceed 360 degree;'\ ' phiedges: %.0f, %.0f' % (phiedges[0], phiedges[-1])) self.pb = HBins(phiedges, nphibins) phi1, phi2 = self.pb.limits() self.is360 = math.fabs(math.fabs(phi2 - phi1) - 360) < 1e-3 def print_attrs(self): print('%s attrbutes:' % self.__class__.__name__) print( self.pb.strrange(fmt='Phi bins: min:%8.1f max:%8.1f nbins:%5d')) print( self.rb.strrange(fmt='Rad bins: min:%8.1f max:%8.1f nbins:%5d')) def print_ndarrs(self): print('%s n-d arrays:' % self.__class__.__name__) if self.print_ndarr is None: from psana.pyalgos.generic.NDArrUtils import print_ndarr self.print_ndarr = print_ndarr self.print_ndarr(self.rad, ' rad') self.print_ndarr(self.phi, ' phi') self.print_ndarr(self.mask, ' mask') #print('Phi limits: ', phiedges[0], phiedges[-1]) def obj_radbins(self): """Returns HBins object for radial bins.""" return self.rb def obj_phibins(self): """Returns HBins object for angular bins.""" return self.pb def pixel_rad(self): """Returns 1-d numpy array of pixel radial parameters.""" return self.rad def pixel_irad(self): """Returns 1-d numpy array of pixel radial indexes.""" return self.irad def pixel_phi0(self): """Returns 1-d numpy array of pixel angules in the range [-180,180] degree.""" return self.phi0 def pixel_phi(self): """Returns 1-d numpy array of pixel angules in the range [phi_min, phi_min+360] degree.""" return self.phi def pixel_iphi(self): """Returns 1-d numpy array of pixel angular indexes.""" return self.iphi def pixel_iseq(self): """Returns 1-d numpy array of sequentially (in rad and phi) numerated pixel indexes.""" return self.iseq def bin_number_of_pixels(self): """Returns 1-d numpy array of number of accounted pixels per bin.""" return self.npix_per_bin def _flatten_(self, nda): if len(nda.shape) > 1: #nda.shape = self.shapeflat return nda.flatten( ) # return flatten copy in order to preserve input array shape return nda def bin_intensity(self, nda): """Returns 1-d numpy array of total pixel intensity per bin for input array nda.""" return np.bincount(self.iseq, weights=self._flatten_(nda), minlength=None) def bin_avrg(self, nda): """Returns 1-d numpy array of averaged in bin intensity for input array nda.""" num = self.bin_intensity(self._flatten_(nda)) den = self.bin_number_of_pixels() return divide_protected(num, den, vsub_zero=0) def bin_avrg_rad_phi(self, nda, do_transp=True): """Returns 2-d (rad,phi) numpy array of averaged in bin intensity for input array nda.""" arr_rphi = self.bin_avrg(self._flatten_(nda))[:-1] arr_rphi.shape = (self.pb.nbins(), self.rb.nbins()) return np.transpose(arr_rphi) if do_transp else arr_rphi def pixel_avrg(self, nda): """Returns 1-d numpy array of per-pixel background for input array nda.""" bin_avrg = self.bin_avrg(self._flatten_(nda)) return np.array([bin_avrg[i] for i in self.iseq]) def pixel_avrg_interpol(self, nda, method='linear', verb=False): # 'nearest' 'cubic' """Returns 1-d numpy array of per-pixel interpolated background for averaged input data.""" #if not is360 : raise ValueError('Interpolation works for 360 degree coverage ONLY') if self.griddata is None: from scipy.interpolate import griddata self.griddata = griddata # 1) get values in bin centers binv = self.bin_avrg_rad_phi(self._flatten_(nda), do_transp=False) # 2) add values in bin edges if verb: print('binv.shape: ', binv.shape) vrad_a1, vrad_a2 = binv[0, :], binv[-1, :] if self.is360: vrad_a1 = vrad_a2 = 0.5 * (binv[0, :] + binv[-1, :] ) # [iphi, irad] nodea = np.vstack((vrad_a1, binv, vrad_a2)) vang_rmin, vang_rmax = nodea[:, 0], nodea[:, -1] vang_rmin.shape = vang_rmax.shape = (vang_rmin.size, 1 ) # it should be 2d for hstack val_nodes = np.hstack((vang_rmin, nodea, vang_rmax)) if verb: print('nodear.shape: ', val_nodes.shape) # 3) extend bin-centers by limits bcentsr = self.rb.bincenters() bcentsp = self.pb.bincenters() blimsr = self.rb.limits() blimsp = self.pb.limits() rad_nodes = np.concatenate(((blimsr[0], ), bcentsr, (blimsr[1], ))) phi_nodes = np.concatenate(((blimsp[0], ), bcentsp, (blimsp[1], ))) if verb: print('rad_nodes.shape', rad_nodes.shape) if verb: print('phi_nodes.shape', phi_nodes.shape) # 4) make point coordinate and value arrays points_rad, points_phi = np.meshgrid(rad_nodes, phi_nodes) if verb: print('points_phi.shape', points_phi.shape) if verb: print('points_rad.shape', points_rad.shape) points = np.array(zip(points_phi.flatten(), points_rad.flatten())) if verb: print('points.shape', points.shape) values = val_nodes.flatten() if verb: print('values.shape', values.shape) # 4) return interpolated data on (phi, rad) grid grid_vals = self.griddata(points, values, (self.phi, self.rad), method=method) return np.select((self.iseq < self.pb.nbins() * self.rb.nbins(), ), (grid_vals, ), default=0)