def test_time_selection(d, second_time, second_dt): """ Test that both 'touching' and 'fully_contained' give the same results as 'strax.fully_contained_in' and 'strax.touching_windows' respectively :param d: test-data from get_dummy_data :param second_dt: the ofset w.r.t. the first :return: None """ container = np.zeros(1, dtype=strax.time_fields) container['time'] = second_time container['endtime'] = second_time + second_dt time_range = (second_time, second_time + second_dt) # Fully contained in selected_data = strax.apply_selection(d, time_range=time_range, time_selection='fully_contained') contained = strax.fully_contained_in(d, container) selected_data_fc = d[contained != -1] assert np.all(selected_data == selected_data_fc) # TW selected_data = strax.apply_selection(d, time_range=time_range, time_selection='touching') windows = strax.touching_windows(d, container, window=0) assert np.diff(windows[0]) == len(selected_data) if len(windows) and len(selected_data): assert np.all(selected_data == d[windows[0][0]:windows[0][1]])
def test_keep_drop_columns(d): """ Test that the keep/drop_columns option of apply selection works. Also test that it does not affect the original array (e.g. if it were to use a view instead of a copy). :param d: test-data from get_dummy_data :return: None """ columns = list(d.dtype.names) selected_data = strax.apply_selection(d, keep_columns=columns[1:]) # Check we din't loose anything of the original array assert columns == list(d.dtype.names) for c in columns[1:]: assert np.all(selected_data[c] == d[c]) for c in columns[:1]: assert c not in selected_data.dtype.names # Repeat test but for drop columns: selected_data = strax.apply_selection(d, drop_columns=columns[:1]) for c in columns[1:]: assert np.all(selected_data[c] == d[c]) for c in columns[:1]: assert c not in selected_data.dtype.names
def compute(self, events, start, end): # General setup res = np.zeros(1, dtype=self.dtype) res['time'] = start res['endtime'] = end # --- Drift time vs R^2 histogram --- res['drift_time_vs_R2_bounds'] = self.config['drift_time_vs_R2_bounds'] dt_r2_events = strax.apply_selection( events, selection_str=self.config['drift_time_vs_R2_cut_string']) res['drift_time_vs_R2_hist'] = self.drift_time_r2_hist(dt_r2_events) # drift time vs. s2 width histogram res['drift_time_vs_s2width_bounds'] = self.config[ 'drift_time_vs_s2width_bounds'] res['drift_time_vs_s2width_hist'] = self.drift_time_s2width_hist( events) # drift time vs. s1 aft histogram res['drift_time_vs_s1aft_bounds'] = self.config[ 'drift_time_vs_s1aft_bounds'] res['drift_time_vs_s1aft_hist'] = self.drift_time_s1aft_hist(events) # s1 area vs. s2 area (log-log) res['s1area_vs_s2area_bounds'] = self.config['s1area_vs_s2area_bounds'] res['s1area_vs_s2area_hist'] = self.s1area_s2area_hist(events) # Other event properties? return res
def compute(self, peaks, lone_hits, start, end): # General setup res = np.zeros(1, dtype=self.dtype) res['time'] = start res['endtime'] = end n_pmt = self.config['n_tpc_pmts'] n_bins = self.config['online_peak_monitor_nbins'] # Bounds for histograms res['area_vs_width_bounds'] = self.config['area_vs_width_bounds'] res['lone_hits_area_bounds'] = self.config['lone_hits_area_bounds'] # -- Peak vs area 2D histogram -- # Always cut out unphysical peaks sel = (peaks['area'] > 0) & (peaks['range_50p_area'] > 0) res['area_vs_width_hist'] = self.area_width_hist(peaks[sel]) del sel # -- Lone hit properties -- # Make a mask with the cuts. # Now only take lone hits that are separated in time. if len(lone_hits): lh_timedelta = lone_hits[1:]['time'] - strax.endtime(lone_hits)[:-1] # Hits on the left are far away? (assume first is because of chunk bound) mask = np.hstack([True, lh_timedelta > self.config['lone_hits_min_gap']]) # Hits on the right are far away? (assume last is because of chunk bound) mask &= np.hstack([lh_timedelta > self.config['lone_hits_min_gap'], True]) else: mask = [] masked_lh = strax.apply_selection(lone_hits[mask], selection_str=self.config['lone_hits_cut_string']) # Make histogram of ADC counts # NB: LONE HITS AREA ARE IN ADC! lone_hit_areas, _ = np.histogram(masked_lh['area'], bins=n_bins, range=self.config['lone_hits_area_bounds']) lone_hit_channel_count, _ = np.histogram(masked_lh['channel'], bins=n_pmt, range=[0, n_pmt]) # Count number of lone-hits per PMT res['lone_hits_area_hist'] = lone_hit_areas res['lone_hits_per_channel'] = lone_hit_channel_count # Clear mask, don't re-use del mask # -- AFT histogram -- aft_b = [0, 1] aft_hist, _ = np.histogram(peaks['area_fraction_top'], bins=n_bins, range=aft_b) res['aft_hist'] = aft_hist res['aft_bounds'] = aft_b # Estimate Single Electron (SE) gain se_hist, se_bins = np.histogram(peaks['area'], bins=n_bins, range=self.config['online_se_bounds']) bin_centers = (se_bins[1:] + se_bins[:-1]) / 2 res['online_se_gain'] = bin_centers[np.argmax(se_hist)] return res
def test_selection_str(d): """ Test selection string. We are going for this example check that selecting the data based on the data field is the same as if we were to use a mask NB: data must have some length! :param d: test-data from get_dummy_data :return: None """ mean_data = np.mean(d['data']) max_data = np.max(d['data']) mask = (d['data'] > mean_data) & (d['data'] < max_data) selections_str = [f'data > {mean_data}', f'data < {max_data}'] selected_data = strax.apply_selection(d, selection_str=selections_str) assert np.all(selected_data == d[mask])
def wrapped_f(context: strax.Context, run_id: str, **kwargs): # Validate arguments known_kwargs = ( 'time_range seconds_range time_within time_selection ' 'ignore_time_warning ' 'selection_str t_reference to_pe config').split() for k in kwargs: if k not in known_kwargs and k not in parameters: # Python itself also raises TypeError for invalid kwargs raise TypeError(f"Unknown argument {k} for {f.__name__}") if 'config' in kwargs: context = context.new_context(config=kwargs['config']) if 'config' in parameters: kwargs['config'] = context.config # Say magic words to enable holoviews if hv_bokeh: # Generally using globals is not great, but it would be # the same as doing a slow import on the top of this file # pylint: disable=global-statement global _hv_bokeh_initialized if not _hv_bokeh_initialized: import holoviews holoviews.extension('bokeh') _hv_bokeh_initialized = True if 'to_pe' in parameters and 'to_pe' not in kwargs: kwargs['to_pe'] = straxen.get_correction_from_cmt( run_id, context.config['gain_model']) # Prepare selection arguments kwargs['time_range'] = context.to_absolute_time_range( run_id, targets=requires, **{ k: kwargs.get(k) for k in ('time_range seconds_range time_within'.split()) }) kwargs.setdefault('time_selection', default_time_selection) kwargs.setdefault('selection_str', None) kwargs['t_reference'], _ = context.estimate_run_start_and_end( run_id, requires) if warn_beyond_sec is not None and not kwargs.get( 'ignore_time_warning'): tr = kwargs['time_range'] if tr is None: sec_requested = float('inf') else: sec_requested = (tr[1] - tr[0]) / int(1e9) if sec_requested > warn_beyond_sec: tr_str = "the entire run" if tr is None else f"{sec_requested} seconds" raise ValueError( f"The author of this mini analysis recommends " f"not requesting more than {warn_beyond_sec} seconds. " f"You are requesting {tr_str}. If you wish to proceed, " "pass ignore_time_warning = True.") # Load required data, if any if len(requires): deps_by_kind = strax.group_by_kind(requires, context=context) for dkind, dtypes in deps_by_kind.items(): if dkind in kwargs: # Already have data, just apply cuts kwargs[dkind] = strax.apply_selection( kwargs[dkind], selection_str=kwargs['selection_str'], time_range=kwargs['time_range'], time_selection=kwargs['time_selection']) else: kwargs[dkind] = context.get_array( run_id, dtypes, selection_str=kwargs['selection_str'], time_range=kwargs['time_range'], time_selection=kwargs['time_selection'], # Arguments for new context, if needed config=kwargs.get('config'), register=kwargs.get('register'), storage=kwargs.get('storage', tuple()), progress_bar=False, ) # If user did not give time kwargs, but the function expects # a time_range, try to add one based on the time range of the data base_dkind = list(deps_by_kind.keys())[0] x = kwargs[base_dkind] if len(x) and kwargs.get('time_range') is None: x0 = x.iloc[0] if isinstance(x, pd.DataFrame) else x[0] try: kwargs.setdefault('time_range', (x0['time'], strax.endtime(x).max())) except AttributeError: # If x is a holoviews dataset, this will fail. pass if 'seconds_range' in parameters: if kwargs.get('time_range') is None: scr = None else: scr = tuple([(t - kwargs['t_reference']) / int(1e9) for t in kwargs['time_range']]) kwargs.setdefault('seconds_range', scr) kwargs.setdefault('run_id', run_id) kwargs.setdefault('context', context) if 'kwargs' in parameters: # Likely this will be passed to another mini-analysis to_pass = kwargs # Do not pass time_range and seconds_range both (unless explicitly requested) # strax does not like that if 'seconds_range' in to_pass and not 'seconds_range' in parameters: del to_pass['seconds_range'] if 'time_within' in to_pass and not 'time_within' in parameters: del to_pass['time_within'] else: # Pass only arguments the function wants to_pass = {k: v for k, v in kwargs.items() if k in parameters} return f(**to_pass)