def test_mc_wrapper_elife( run_id='009000', cmt_id='016000', mc_id='mc_0', ): """ Test that for two different run ids, we get different elifes using the MC wrapper. :param run_id: First run-id (used for normal query) :param cmt_id: Second run-id used as a CMT id (should not be the same as run_id! otherwise the values might actually be the same and the test does not work). :return: None """ if not straxen.utilix_is_configured(): return assert np.abs(int(run_id) - int(cmt_id)) > 500, 'runs must be far apart' # First for the run-id let's get the value elife = straxen.get_correction_from_cmt(run_id, ("elife", "ONLINE", True)) # Now, we repeat the same query using the MC wrapper, this should # give us a different result since we are now asking for a very # different run-number. mc_elife_diff = straxen.get_correction_from_cmt( mc_id, ('MC', cmt_id, "elife", "ONLINE", True)) # Repeat the query from above to verify, let's see if we are getting # the same results as for `elife` above mc_elife_same = straxen.get_correction_from_cmt( mc_id, ('MC', run_id, "elife", "ONLINE", True)) assert elife != mc_elife_diff assert elife == mc_elife_same
def set_config(self, ): self.config.update( straxen.get_resource(self.config['fax_config'], fmt='json')) overrides = self.config['fax_config_override'] if overrides is not None: self.config.update(overrides) # backwards compatibility if 'field_distortion_on' in self.config and not 'field_distortion_model' in self.config: self.config.update({ 'field_distortion_model': "inverse_fdc" if self.config['field_distortion_on'] else "none" }) # Update gains to the nT defaults self.to_pe = straxen.get_correction_from_cmt( self.run_id, self.config['gain_model_mc']) adc_2_current = (self.config['digitizer_voltage_range'] / 2**(self.config['digitizer_bits']) / self.config['pmt_circuit_load_resistor']) self.config['gains'] = np.divide(adc_2_current, self.to_pe, out=np.zeros_like(self.to_pe), where=self.to_pe != 0) if self.config['seed']: np.random.seed(self.config['seed']) # We hash the config to load resources. Channel map is immutable and cannot be hashed self.config['channel_map'] = dict(self.config['channel_map']) self.config['channel_map']['sum_signal'] = 800 self.config['channels_bottom'] = np.arange(self.config['n_top_pmts'], self.config['n_tpc_pmts']) # Update some values stored in CMT if self.config['fax_config_override_from_cmt'] is not None: for fax_field, cmt_option in self.config[ 'fax_config_override_from_cmt'].items(): if (fax_field in ['fdc_3d', 's1_light_yield_map'] and self.config.get('default_reconstruction_algorithm', False)): cmt_option = tuple([ 'suffix', self.config['default_reconstruction_algorithm'], *cmt_option ]) cmt_value = straxen.get_correction_from_cmt( self.run_id, cmt_option) log.warning( f'Replacing {fax_field} with CMT option {cmt_option} to {cmt_value}' ) self.config[fax_field] = cmt_value
def setup(self): self.mean_pe_photon = self.config['mean_pe_per_photon'] # Getting S1 AFT maps self.s1_aft_map = straxen.InterpolatingMap( straxen.get_resource( self.config['s1_aft_map'], fmt=self._infer_map_format(self.config['s1_aft_map']))) # Getting optical maps self.s1_pattern_map = straxen.InterpolatingMap( straxen.get_resource( self.config['s1_optical_map'], fmt=self._infer_map_format(self.config['s1_optical_map']))) self.s2_pattern_map = straxen.InterpolatingMap( straxen.get_resource( self.config['s2_optical_map'], fmt=self._infer_map_format(self.config['s2_optical_map']))) # Getting gain model to get dead PMTs self.to_pe = straxen.get_correction_from_cmt(self.run_id, self.config['gain_model']) self.dead_PMTs = np.where(self.to_pe == 0)[0] self.pmtbool = ~np.in1d(np.arange(0, self.config['n_tpc_pmts']), self.dead_PMTs) self.pmtbool_top = self.pmtbool[:self.config['n_top_pmts']] self.pmtbool_bottom = self.pmtbool[self.config['n_top_pmts']:self.config['n_tpc_pmts']]
def setup(self): self.to_pe = straxen.get_correction_from_cmt(self.run_id, self.config['gain_model']) buffer_pmts = np.zeros(self.config['he_channel_offset']) self.to_pe = np.concatenate((buffer_pmts, self.to_pe)) self.to_pe *= self.config['le_to_he_amplification']
def setup(self): self.to_pe = straxen.get_correction_from_cmt(self.run_id, self.config['gain_model']) self.hit_left_extension, self.hit_right_extension = self.config[ 'save_outside_hits'] # Check config of `hit_min_amplitude` and define hit thresholds # if cmt config if is_cmt_option(self.config['hit_min_amplitude']): self.hit_thresholds = straxen.get_correction_from_cmt( self.run_id, self.config['hit_min_amplitude']) # if hitfinder_thresholds config elif isinstance(self.config['hit_min_amplitude'], str): self.hit_thresholds = straxen.hit_min_amplitude( self.config['hit_min_amplitude']) else: # int or array self.hit_thresholds = self.config['hit_min_amplitude']
def test_cmt_conf_option(option='mlp_model', version='ONLINE', is_nT=True): """ Test CMT conf options If wrong conf is passed it would raise an error accordingly """ conf = option, version, is_nT correction = straxen.get_correction_from_cmt(test_run_id_nT, conf) assert isinstance(correction, (float, int, str, np.ndarray))
def setup(self): if isinstance(self.config['baseline_samples_nv'], int): self.baseline_samples = self.config['baseline_samples_nv'] else: self.baseline_samples = straxen.get_correction_from_cmt( self.run_id, self.config['baseline_samples_nv']) # Check config of `hit_min_amplitude_nv` and define hit thresholds # if cmt config if is_cmt_option(self.config['hit_min_amplitude_nv']): self.hit_thresholds = straxen.get_correction_from_cmt(self.run_id, self.config['hit_min_amplitude_nv']) # if hitfinder_thresholds config elif isinstance(self.config['hit_min_amplitude_nv'], str): self.hit_thresholds = straxen.hit_min_amplitude( self.config['hit_min_amplitude_nv']) else: # int or array self.hit_thresholds = self.config['hit_min_amplitude_nv']
def setup(self): self.hev_enabled = ((self.config['hev_gain_model'][0] != 'disabled') and self.config['tail_veto_threshold']) if self.hev_enabled: self.to_pe = straxen.get_correction_from_cmt( self.run_id, self.config['hev_gain_model']) # Check config of `hit_min_amplitude` and define hit thresholds # if cmt config if is_cmt_option(self.config['hit_min_amplitude']): self.hit_thresholds = straxen.get_correction_from_cmt( self.run_id, self.config['hit_min_amplitude']) # if hitfinder_thresholds config elif isinstance(self.config['hit_min_amplitude'], str): self.hit_thresholds = straxen.hit_min_amplitude( self.config['hit_min_amplitude']) else: # int or array self.hit_thresholds = self.config['hit_min_amplitude']
def get_correction(name: str, run_id: str = None, version: str = 'ONLINE', detector: str = 'nt', **kwargs): """Get value for name from CMT""" if run_id is None: raise ValueError('Attempting to fetch a correction without a run id.') return straxen.get_correction_from_cmt(run_id, (name, version, detector == 'nt'))
def setup(self): if self.config['peak_min_pmts'] > 2: # Can fix by re-splitting, raise NotImplementedError( f"Raising the peak_min_pmts to {self.config['peak_min_pmts']} " f"interferes with lone_hit definition. " f"See github.com/XENONnT/straxen/issues/295") self.to_pe = straxen.get_correction_from_cmt(self.run_id, self.config['gain_model'])
def setup(self): self.channel_range = self.config['channel_map']['mv'] self.n_channel = (self.channel_range[1] - self.channel_range[0]) + 1 to_pe = straxen.get_correction_from_cmt(self.run_id, self.config['gain_model_mv']) # Create to_pe array of size max channel: self.to_pe = np.zeros(self.channel_range[1] + 1, dtype=np.float32) self.to_pe[self.channel_range[0]:] = to_pe[:]
def test_cmt_conf_option(option='mlp_model', version='ONLINE', is_nT=True): """ Test CMT conf options If wrong conf is passed it would raise an error accordingly """ if not straxen.utilix_is_configured(): warn('Cannot do test becaus ' 'no have access to the database.') return conf = option, version, is_nT correction = straxen.get_correction_from_cmt(test_run_id_nT, conf) assert isinstance(correction, (float, int, str, np.ndarray))
def test_1T_elife(): """ Test elife from CMT DB against historical data(aux file) """ elife_conf = ('elife_xenon1t', 'ONLINE', False) elife_cmt = straxen.get_correction_from_cmt(test_run_id_1T, elife_conf) elife_file = aux_repo + '3548132b55f81a43654dba5141366041e1daaf01/strax_files/elife.npy' x = straxen.get_resource(elife_file, fmt='npy') run_index = np.where(x['run_id'] == int(test_run_id_1T))[0] elife = x[run_index[0]]['e_life'] mes = 'Elife values do not match. Please check' assert elife_cmt == elife, mes
def setup(self): self.to_pe = straxen.get_correction_from_cmt(self.run_id, self.config['gain_model']) buffer_pmts = np.zeros(self.config['he_channel_offset']) self.to_pe = np.concatenate((buffer_pmts, self.to_pe)) self.to_pe *= self.config['le_to_he_amplification'] # Check config of `hit_min_amplitude_he` and define hit thresholds # if cmt config if is_cmt_option(self.config['hit_min_amplitude_he']): self.hit_thresholds = straxen.get_correction_from_cmt( self.run_id, self.config['hit_min_amplitude_he']) # if hitfinder_thresholds config elif isinstance(self.config['hit_min_amplitude_he'], str): self.hit_thresholds = straxen.hit_min_amplitude( self.config['hit_min_amplitude_he']) else: # int or array self.hit_thresholds = self.config['hit_min_amplitude_he'] self.channel_range = self.config['channel_map']['he']
def test_mc_wrapper_gains( run_id='009000', cmt_id='016000', mc_id='mc_0', execute=True, ): """ Test that for two different run ids, we get different gains using the MC wrapper. :param run_id: First run-id (used for normal query) :param cmt_id: Second run-id used as a CMT id (should not be the same as run_id! otherwise the values might actually be the same and the test does not work). :param execute: Execute this test (this is set to False since the test takes 9 minutes which is too long. We can activate this if the testing time due to faster CMT queries is reduced). :return: None """ if not straxen.utilix_is_configured() or not execute: return assert np.abs(int(run_id) - int(cmt_id)) > 500, 'runs must be far apart' # First for the run-id let's get the value gains = straxen.get_correction_from_cmt(run_id, ('to_pe_model', 'ONLINE', True)) # Now, we repeat the same query using the MC wrapper, this should # give us a different result since we are now asking for a very # different run-number. mc_gains_diff = straxen.get_correction_from_cmt( mc_id, ('MC', cmt_id, 'to_pe_model', 'ONLINE', True)) # Repeat the query from above to verify, let's see if we are getting # the same results as for `gains` above mc_gains_same = straxen.get_correction_from_cmt( mc_id, ('MC', run_id, 'to_pe_model', 'ONLINE', True)) assert not np.all(gains == mc_gains_diff) assert np.all(gains == mc_gains_same)
def setup(self): self.channel_range = self.config['channel_map']['nveto'] self.n_channel = (self.channel_range[1] - self.channel_range[0]) + 1 to_pe = straxen.get_correction_from_cmt(self.run_id, self.config['gain_model_nv']) # Create to_pe array of size max channel: self.to_pe = np.zeros(self.channel_range[1] + 1, dtype=np.float32) self.to_pe[self.channel_range[0]:] = to_pe[:] # Check config of `hit_min_amplitude_nv` and define hit thresholds # if cmt config if is_cmt_option(self.config['hit_min_amplitude_nv']): self.hit_thresholds = straxen.get_correction_from_cmt( self.run_id, self.config['hit_min_amplitude_nv']) # if hitfinder_thresholds config elif isinstance(self.config['hit_min_amplitude_nv'], str): self.hit_thresholds = straxen.hit_min_amplitude( self.config['hit_min_amplitude_nv']) else: # int or array self.hit_thresholds = self.config['hit_min_amplitude_nv']
def setup(self): self.electron_drift_velocity = get_correction_from_cmt( self.run_id, self.config['electron_drift_velocity']) self.electron_drift_time_gate = get_correction_from_cmt( self.run_id, self.config['electron_drift_time_gate']) self.mean_pe_photon = self.config['mean_pe_per_photon'] # Getting S1 AFT maps self.s1_aft_map = straxen.InterpolatingMap( straxen.get_resource(self.config['s1_aft_map'], fmt=self._infer_map_format( self.config['s1_aft_map']))) # Getting optical maps self.s1_pattern_map = straxen.InterpolatingMap( straxen.get_resource(self.config['s1_optical_map'], fmt=self._infer_map_format( self.config['s1_optical_map']))) self.s2_pattern_map = straxen.InterpolatingMap( straxen.get_resource(self.config['s2_optical_map'], fmt=self._infer_map_format( self.config['s2_optical_map']))) # Getting S2 data-driven tensorflow models downloader = straxen.MongoDownloader() self.model_file = downloader.download_single( self.config['s2_tf_model']) with tempfile.TemporaryDirectory() as tmpdirname: tar = tarfile.open(self.model_file, mode="r:gz") tar.extractall(path=tmpdirname) import tensorflow as tf def _logl_loss(patterns_true, likelihood): return likelihood / 10. self.model = tf.keras.models.load_model( tmpdirname, custom_objects={"_logl_loss": _logl_loss}) self.model_chi2 = tf.keras.Model( self.model.inputs, self.model.get_layer('Likelihood').output) # Getting gain model to get dead PMTs self.to_pe = straxen.get_correction_from_cmt(self.run_id, self.config['gain_model']) self.dead_PMTs = np.where(self.to_pe == 0)[0] self.pmtbool = ~np.in1d(np.arange(0, self.config['n_tpc_pmts']), self.dead_PMTs) self.pmtbool_top = self.pmtbool[:self.config['n_top_pmts']] self.pmtbool_bottom = self.pmtbool[self.config['n_top_pmts']:self. config['n_tpc_pmts']]
def setup(self): if self.config['peak_min_pmts'] > 2: # Can fix by re-splitting, raise NotImplementedError( f"Raising the peak_min_pmts to {self.config['peak_min_pmts']} " f"interferes with lone_hit definition. " f"See github.com/XENONnT/straxen/issues/295") self.to_pe = straxen.get_correction_from_cmt(self.run_id, self.config['gain_model']) # Check config of `hit_min_amplitude` and define hit thresholds # if cmt config if is_cmt_option(self.config['hit_min_amplitude']): self.hit_thresholds = straxen.get_correction_from_cmt( self.run_id, self.config['hit_min_amplitude']) # if hitfinder_thresholds config elif isinstance(self.config['hit_min_amplitude'], str): self.hit_thresholds = straxen.hit_min_amplitude( self.config['hit_min_amplitude']) else: # int or array self.hit_thresholds = self.config['hit_min_amplitude'] self.channel_range = self.config['channel_map']['tpc']
def setup(self): self.hev_enabled = False self.config['n_tpc_pmts'] = self.config['n_he_pmts'] # Check config of `hit_min_amplitude` and define hit thresholds # if cmt config if is_cmt_option(self.config['hit_min_amplitude_he']): self.hit_thresholds = straxen.get_correction_from_cmt( self.run_id, self.config['hit_min_amplitude_he']) # if hitfinder_thresholds config elif isinstance(self.config['hit_min_amplitude_he'], str): self.hit_thresholds = straxen.hit_min_amplitude( self.config['hit_min_amplitude_he']) else: # int or array self.hit_thresholds = self.config['hit_min_amplitude_he']
def test_1T_elife(): """ Test elife from CMT DB against historical data(aux file) """ if not straxen.utilix_is_configured(): warn('Cannot do test becaus ' 'no have access to the database.') return elife_conf = ('elife', 'ONLINE', False) elife_cmt = straxen.get_correction_from_cmt(test_run_id_1T, elife_conf) elife_file = elife_conf = aux_repo + '3548132b55f81a43654dba5141366041e1daaf01/strax_files/elife.npy' x = straxen.get_resource(elife_file, fmt='npy') run_index = np.where(x['run_id'] == int(test_run_id_1T))[0] elife = x[run_index[0]]['e_life'] mes = 'Elife values do not match. Please check' assert elife_cmt == elife, mes
def _get_model_file_name(self): config_file = f'{self.algorithm}_model' model_from_config = self.config.get(config_file, 'No file') if model_from_config == 'No file': raise ValueError(f'{__class__.__name__} should have {config_file} ' f'provided as an option.') if isinstance(model_from_config, str) and os.path.exists(model_from_config): # Allow direct path specification return model_from_config if model_from_config is None: # Allow None to be specified (disables processing for given posrec) return model_from_config # Use CMT model_file = straxen.get_correction_from_cmt(self.run_id, model_from_config) return model_file
def set_config(self, ): super().set_config() if 'nveto' in self.config['targets']: self.config_nveto = deepcopy(self.config) self.config_nveto.update( straxen.get_resource(self.config_nveto['fax_config_nveto'], fmt='json')) self.config_nveto['detector'] = 'XENONnT_neutron_veto' self.config_nveto['channel_map'] = dict( self.config_nveto['channel_map']) overrides = self.config['fax_config_override_nveto'] if overrides is not None: self.config_nveto.update(overrides) self.to_pe_nveto = straxen.get_correction_from_cmt( self.run_id, self.config['gain_model_nv']) self.config_nveto['gains'] = np.divide( (2e-9 * 2 / 2**14) / (1.6e-19 * 1 * 50), self.to_pe_nveto, out=np.zeros_like(self.to_pe_nveto), where=self.to_pe_nveto != 0) self.config_nveto['channels_bottom'] = np.array([], np.int64)
def setup(self): self.hev_enabled = ((self.config['hev_gain_model'][0] != 'disabled') and self.config['tail_veto_threshold']) if self.hev_enabled: self.to_pe = straxen.get_correction_from_cmt( self.run_id, self.config['hev_gain_model'])
def setup(self): self.to_pe = straxen.get_correction_from_cmt(self.run_id, self.config['gain_model'])
def load_corrected_positions(context, run_id, events, alt_s1=False, alt_s2=False, cmt_version=None, posrec_algos=('mlp', 'gcn', 'cnn')): """ Returns the corrected position for each position algorithm available, without the need to reprocess event_basics, as the needed information is already stored in event_basics. :param alt_s1: False by default, if True it uses alternative S1 as main one :param alt_s2: False by default, if True it uses alternative S2 as main one :param cmt_version: CMT version to use (it can be a list of same length as posrec_algos, if different versions are required for different posrec algorithms, default 'local_ONLINE') :param posrec_algos: list of position reconstruction algorithms to use (default ['mlp', 'gcn', 'cnn']) """ posrec_algos = strax.to_str_tuple(posrec_algos) if cmt_version is None: fdc_config = context.get_single_plugin( run_id, 'event_positions').config['fdc_map'] if isinstance(fdc_config, str) and 'cmt://' in fdc_config: cmt_version = straxen.URLConfig.split_url_kwargs(fdc_config) elif straxen.is_cmt_option(fdc_config): cmt_version = fdc_config[1] else: raise ValueError( 'FDC map is not a CMT option, cannot infer cmt version.') if (isinstance(cmt_version, (tuple, list)) and len(cmt_version) != len(posrec_algos)): raise TypeError(f"cmt_version is a list but does not match the " f"posrec_algos ({posrec_algos}) length.") cmt_version = ((cmt_version, ) * len(posrec_algos) if isinstance( cmt_version, str) else cmt_version) # Get drift from CMT ep = context.get_single_plugin(run_id, 'event_positions') drift_speed = ep.electron_drift_velocity drift_time_gate = ep.electron_drift_time_gate dtype = load_dtypes(posrec_algos) result = np.zeros(len(events), dtype=dtype) s1_pre = 'alt_' if alt_s1 else '' s2_pre = 'alt_' if alt_s2 else '' drift_time = events['drift_time'] if not (alt_s1 or alt_s2) else events[ s2_pre + 's2_center_time'] - events[s1_pre + 's1_center_time'] z_obs = -drift_speed * drift_time for algo, v_cmt in zip(posrec_algos, cmt_version): fdc_tmp = (f'fdc_map_{algo}', v_cmt, True) map_tmp = straxen.get_correction_from_cmt(run_id, fdc_tmp) itp_tmp = straxen.InterpolatingMap( straxen.common.get_resource(map_tmp, fmt='binary')) itp_tmp.scale_coordinates([1., 1., -drift_speed]) orig_pos = np.vstack([ events[f'{s2_pre}s2_x_{algo}'], events[f'{s2_pre}s2_y_{algo}'], z_obs ]).T r_obs = np.linalg.norm(orig_pos[:, :2], axis=1) delta_r = itp_tmp(orig_pos) z_obs = z_obs + drift_speed * drift_time_gate # apply radial correction with np.errstate(invalid='ignore', divide='ignore'): r_cor = r_obs + delta_r scale = r_cor / r_obs with np.errstate(invalid='ignore'): z_cor = -(z_obs**2 - delta_r**2)**0.5 invalid = np.abs(z_obs) < np.abs(delta_r) z_cor[invalid] = z_obs[invalid] result[f'x_{algo}'] = orig_pos[:, 0] * scale result[f'y_{algo}'] = orig_pos[:, 1] * scale result[f'r_{algo}'] = r_cor result[f'r_naive_{algo}'] = r_obs result[f'r_field_distortion_correction_{algo}'] = delta_r result[f'theta_{algo}'] = np.arctan2(orig_pos[:, 1], orig_pos[:, 0]) result[f'z_{algo}'] = z_cor result['z_naive'] = z_obs return result
def plot_pulses(context, raw_records, run_id, time_range, plot_hits=False, plot_median=False, max_plots=20, store_pdf=False, path='', detector_ending=''): """ Plots nveto pulses for a list of records. :param context: Context to be used. :param plot_hits: If True plot hit boundaries including the left and right extension as orange shaded regions. :param plot_median: If true plots pulses sample median as dotted line. :param max_plots: Limits the number of figures. If you would like to plot more pulses you should put the plots in a PDF. :param store_pdf: If true figures are put to a PDF instead of plotting them to your notebook. The file name is automatically generated including the time range and run_id. :param path: Relative path where the PDF should be stored. By default it is the directory of the notebook. :param detector_ending: Ending of the corresponding detector. Empty string for TPC '_nv' for neutron-veto and '_mv' muon-veto. """ # Register records plugin to get settings p = context.get_single_plugin(run_id, 'records' + detector_ending) # Compute strax baseline and baseline_rms: records = strax.raw_to_records(raw_records) records = strax.sort_by_time(records) strax.zero_out_of_bounds(records) baseline_key = [ key for key in p.config.keys() if 'baseline_samples' in key ][0] if isinstance(p.config[baseline_key], int): baseline_samples = p.config[baseline_key] else: baseline_samples = straxen.get_correction_from_cmt( run_id, p.config[baseline_key]) strax.baseline(records, baseline_samples=baseline_samples, flip=True) nfigs = 1 if store_pdf and time_range is None: raise ValueError(f'Specify time range!') if store_pdf: from matplotlib.backends.backend_pdf import PdfPages fname = f'pulses_{run_id}_{time_range[0]}_{time_range[1]}.pdf' fname = os.path.join(path, fname) pdf = PdfPages(fname) hits = None # needed for delete if false for inds in _yield_pulse_indices(raw_records): # Grouped our pulse so now plot: rr_pulse = raw_records[inds] r_pulse = records[inds] fig, axes = straxen.plot_single_pulse(rr_pulse, run_id) if detector_ending == '_nv': # We only store for the nv digitizer baseline values: axes.axhline(rr_pulse[0]['baseline'], ls='dashed', color='k', label=f'D. Bas.: {rr_pulse[0]["baseline"]} ADC') baseline = r_pulse[0]['baseline'] baseline_rms = r_pulse[0]['baseline_rms'] axes.axhline( baseline, ls='solid', color='k', label= f'Strax Bas. +/-RMS:\n ({baseline:.2f}+/-{baseline_rms:.2f}) ADC') xlim = axes.get_xlim() axes.fill_between(xlim, [baseline + baseline_rms] * 2, [baseline - baseline_rms] * 2, color='gray', alpha=0.4) # check type of p.hit_thresholds if isinstance(p.hit_thresholds, int): thr = p.hit_thresholds elif isinstance(p.hit_thresholds, np.ndarray): thr = p.hit_thresholds[rr_pulse['channel']][0] if plot_median: # Plot median if asked. # Have to make pulse again: pulse = straxen.matplotlib_utils._make_pulse(rr_pulse) median = np.median(pulse) axes.axhline(median, ls='dotted', color='k', label=f'Median Bas.: {median:.0f} ADC') axes.axhline(median - thr, ls='dotted', color='orange') if plot_hits: min_amplitude = thr axes.axhline(baseline - min_amplitude, color='orange', label='Hitfinder threshold') hits = strax.find_hits(r_pulse, min_amplitude=min_amplitude) if detector_ending != '_he': # We don't have 'save_outside_hits_he' at all! le, re = p.config['save_outside_hits' + detector_ending] else: le, re = p.config['save_outside_hits'] start = (hits['time'] - r_pulse[0]['time']) / r_pulse[0]['dt'] - le end = (strax.endtime(hits) - r_pulse[0]['time']) / r_pulse[0]['dt'] + re ylim = axes.get_ylim() for s, e in zip(start, end): plt.fill_between((s, e), *ylim, alpha=0.2, color='orange') axes.set_ylim(*ylim) plt.legend() axes.set_xlim(*xlim) if store_pdf: plt.close() pdf.savefig(fig) nfigs += 1 if max_plots is not None and nfigs > max_plots: break if store_pdf: pdf.close() del records, hits
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)
def setup(self): if isinstance(self.config['baseline_samples_nv'], int): self.baseline_samples = self.config['baseline_samples_nv'] else: self.baseline_samples = straxen.get_correction_from_cmt( self.run_id, self.config['baseline_samples_nv'])
def load_corrected_positions(context, run_id, events, cmt_version=None, posrec_algos=('mlp', 'gcn', 'cnn')): """ Returns the corrected position for each position algorithm available, without the need to reprocess event_basics, as the needed information is already stored in event_basics. :param cmt_version: CMT version to use (it can be a list of same length as posrec_algos, if different versions are required for different posrec algorithms, default 'local_ONLINE') :param posrec_algos: list of position reconstruction algorithms to use (default ['mlp', 'gcn', 'cnn']) """ posrec_algos = strax.to_str_tuple(posrec_algos) if cmt_version is None: fdc_config = None try: fdc_config = context.get_single_plugin( run_id, 'event_positions').config['fdc_map'] cmt_version = fdc_config[1] except IndexError as e: raise ValueError( f'CMT is not set? Your fdc config is {fdc_config}') from e if (isinstance(cmt_version, (tuple, list)) and len(cmt_version) != len(posrec_algos)): raise TypeError(f"cmt_version is a list but does not match the " f"posrec_algos ({posrec_algos}) length.") cmt_version = ((cmt_version, ) * len(posrec_algos) if isinstance( cmt_version, str) else cmt_version) # Get drift from CMT ep = context.get_single_plugin(run_id, 'event_positions') drift_conf = ep.config.get('electron_drift_velocity') drift_speed = straxen.get_correction_from_cmt(run_id, drift_conf) dtype = [] for algo in posrec_algos: for xyzr in 'x y z r'.split(): dtype += [ ((f'Interaction {xyzr}-position, field-distortion corrected (cm) - ' f'{algo.upper()} posrec algorithm', f'{xyzr}_{algo}'), np.float32), ] dtype += [(( f'Interaction r-position using observed S2 positions directly (cm) -' f' {algo.upper()} posrec algorithm', f'r_naive_{algo}'), np.float32), ((f'Correction added to r_naive for field distortion (cm) - ' f'{algo.upper()} posrec algorithm', f'r_field_distortion_correction_{algo}'), np.float32), ((f'Interaction angular position (radians) - {algo.upper()} ' f'posrec algorithm', f'theta_{algo}'), np.float32)] dtype += [(('Interaction z-position using mean drift velocity only (cm)', 'z_naive'), np.float32)] result = np.zeros(len(events), dtype=dtype) z_obs = -drift_speed * events['drift_time'] for algo, v_cmt in zip(posrec_algos, cmt_version): fdc_tmp = (f'fdc_map_{algo}', v_cmt, True) map_tmp = straxen.get_correction_from_cmt(run_id, fdc_tmp) itp_tmp = straxen.InterpolatingMap( straxen.common.get_resource(map_tmp, fmt='binary')) itp_tmp.scale_coordinates([1., 1., -drift_speed]) orig_pos = np.vstack( [events[f's2_x_{algo}'], events[f's2_y_{algo}'], z_obs]).T r_obs = np.linalg.norm(orig_pos[:, :2], axis=1) delta_r = itp_tmp(orig_pos) # apply radial correction with np.errstate(invalid='ignore', divide='ignore'): r_cor = r_obs + delta_r scale = r_cor / r_obs with np.errstate(invalid='ignore'): z_cor = -(z_obs**2 - delta_r**2)**0.5 invalid = np.abs(z_obs) < np.abs(delta_r) z_cor[invalid] = z_obs[invalid] result[f'x_{algo}'] = orig_pos[:, 0] * scale result[f'y_{algo}'] = orig_pos[:, 1] * scale result[f'r_{algo}'] = r_cor result[f'r_naive_{algo}'] = r_obs result[f'r_field_distortion_correction_{algo}'] = delta_r result[f'theta_{algo}'] = np.arctan2(orig_pos[:, 1], orig_pos[:, 0]) result[f'z_{algo}'] = z_cor result['z_naive'] = z_obs return result