def compute(self, records_nv, start, end): hits = strax.find_hits(records_nv, min_amplitude=self.config['hit_min_amplitude_nv']) hits = remove_switched_off_channels(hits, self.to_pe) temp_hitlets = strax.create_hitlets_from_hits(hits, self.config['save_outside_hits_nv'], self.channel_range, chunk_start=start, chunk_end=end) del hits # Get hitlet data and split hitlets: temp_hitlets = strax.get_hitlets_data(temp_hitlets, records_nv, to_pe=self.to_pe) temp_hitlets = strax.split_peaks(temp_hitlets, records_nv, self.to_pe, data_type='hitlets', algorithm='local_minimum', min_height=self.config['min_split_nv'], min_ratio=self.config['min_split_ratio_nv'] ) # Compute other hitlet properties: # We have to loop here 3 times over all hitlets... strax.hitlet_properties(temp_hitlets) entropy = strax.conditional_entropy(temp_hitlets, template='flat', square_data=False) temp_hitlets['entropy'][:] = entropy # Remove data field: hitlets = np.zeros(len(temp_hitlets), dtype=strax.hitlet_dtype()) strax.copy_to_buffer(temp_hitlets, hitlets, '_copy_hitlets') return hitlets
def compute(self, records_nv, start, end): # Search again for hits in records: hits = strax.find_hits( records_nv, min_amplitude=self.config['hit_min_amplitude_nv']) # Merge concatenate overlapping within a channel. This is important # in case hits were split by record boundaries. In case we # accidentally concatenate two PMT signals we split them later again. hits = strax.concat_overlapping_hits( hits, self.config['save_outside_hits_nv'], self.config['channel_map']['nveto'], start, end) hits = strax.sort_by_time(hits) # Now convert hits into temp_hitlets including the data field: if len(hits): nsamples = hits['length'].max() else: nsamples = 0 temp_hitlets = np.zeros( len(hits), strax.hitlet_with_data_dtype(n_samples=nsamples)) # Generating hitlets and copying relevant information from hits to hitlets. # These hitlets are not stored in the end since this array also contains a data # field which we will drop later. strax.refresh_hit_to_hitlets(hits, temp_hitlets) del hits # Get hitlet data and split hitlets: strax.get_hitlets_data(temp_hitlets, records_nv, to_pe=self.to_pe) temp_hitlets = strax.split_peaks( temp_hitlets, records_nv, self.to_pe, data_type='hitlets', algorithm='local_minimum', min_height=self.config['min_split_nv'], min_ratio=self.config['min_split_ratio_nv']) # Compute other hitlet properties: # We have to loop here 3 times over all hitlets... strax.hitlet_properties(temp_hitlets) entropy = strax.conditional_entropy(temp_hitlets, template='flat', square_data=False) temp_hitlets['entropy'][:] = entropy strax.compute_widths(temp_hitlets) # Remove data field: hitlets = np.zeros(len(temp_hitlets), dtype=strax.hitlet_dtype()) drop_data_field(temp_hitlets, hitlets) return hitlets
def test_hitlet_properties(hits_n_data): """ Function which tests refresh_hit_to_hitlets, hitlet_with_data_dtype, and hitlet_properties. :param hits_n_data: :return: """ hits, data = hits_n_data hits['time'] += 100 # Step 1.: Produce fake hits and convert them into hitlets: nsamples = 0 if len(hits) >= 1: nsamples = hits['length'].max() nsamples = np.max((nsamples, 2)) hitlets = np.zeros(len(hits), dtype=strax.hitlet_with_data_dtype(nsamples)) if len(hitlets): assert hitlets['data'].shape[ 1] >= 2, 'Data buffer is not at least 2 samples long.' strax.copy_to_buffer(hits, hitlets, '_refresh_hit_to_hitlet_properties_test') # Testing refresh_hit_to_hitlets for free: assert len(hits) == len( hitlets), 'Somehow hitlets and hits have different sizes' # Testing interval fields: dummy = np.zeros(0, dtype=strax.interval_dtype) for name in dummy.dtype.names: assert np.all(hitlets[name] == hits[name]), f'The entry of the field {name} did not match between hit and ' \ f'hitlets ' # Step 2.: Add to each hit(let) some data for ind, d in enumerate(data): h = hitlets[ind] h['data'][:h['length']] = d[:h['length']] # Step 3.: Add np.nan in data but outside of length: for h in hitlets: if h['length'] < len(h['data']): h['data'][-1] = np.nan # It is enough to test this for a single hitlet: break # Step 4.: Compute properties and apply tests: strax.hitlet_properties(hitlets) for ind, d in enumerate(data): h = hitlets[ind] d = d[:h['length']] pos_max = np.argmax(d) # Checking amplitude things: assert pos_max == h[ 'time_amplitude'], 'Wrong amplitude position found!' assert d[pos_max] == h['amplitude'], 'Wrong amplitude value found!' # Checking FHWM and FWTM: fractions = [0.1, 0.5] for f in fractions: # Get field names for the correct test: if f == 0.5: left = 'left' fwxm = 'fwhm' else: left = 'low_left' fwxm = 'fwtm' amplitude = np.max(d) if np.all(d[0] == d) or np.all(d > amplitude * f): # If all samples are either the same or greater than required height FWXM is not defined: mes = 'All samples are the same or larger than require height.' assert np.isnan( h[left] ), mes + f' Left edge for {f} should have been np.nan.' assert np.isnan( h[left]), mes + f' FWXM for X={f} should have been np.nan.' else: le = np.argwhere(d[:pos_max] <= amplitude * f) if len(le): le = le[-1, 0] m = d[le + 1] - d[le] le = le + 0.5 + (amplitude * f - d[le]) / m else: le = 0 re = np.argwhere(d[pos_max:] <= amplitude * f) if len(re) and re[0, 0] != 0: re = re[0, 0] + pos_max m = d[re] - d[re - 1] re = re + 0.5 + (amplitude * f - d[re]) / m else: re = len(d) assert math.isclose( le, h[left], rel_tol=10**-4, abs_tol=10** -4), f'Left edge does not match for fraction {f}' assert math.isclose( re - le, h[fwxm], rel_tol=10**-4, abs_tol=10**-4), f'FWHM does not match for {f}'
def test_hitlet_properties(hits_n_data): """ Function which tests refresh_hit_to_hitlets, hitlet_with_data_dtype, and hitlet_properties. :param hits_n_data: :return: """ hits, data = hits_n_data hits['time'] += 100 # Step 1.: Produce fake hits and convert them into hitlets: if len(hits) >= 1: nsamples = hits['length'].max() else: nsamples = 2 hitlets = np.zeros(len(hits), dtype=strax.hitlet_with_data_dtype(nsamples)) if len(hitlets): assert hitlets['data'].shape[ 1] >= 2, 'Data buffer is not at least 2 samples long.' strax.refresh_hit_to_hitlets(hits, hitlets) # Testing refresh_hit_to_hitlets for free: assert len(hits) == len( hitlets), 'Somehow hitlets and hits have different sizes' # Tetsing interval fields: dummy = np.zeros(0, dtype=strax.interval_dtype) for name in dummy.dtype.names: assert np.all(hitlets[name] == hits[name]), f'The entry of the field {name} did not match between hit and ' \ f'hitlets ' # Step 2.: Add to each hit(let) some data for ind, d in enumerate(data): h = hitlets[ind] h['data'][:h['length']] = d[:h['length']] strax.hitlet_properties(hitlets) # Step 4.: Apply tests. for ind, d in enumerate(data): h = hitlets[ind] d = d[:h['length']] pos_max = np.argmax(d) # Checking amplitude things: assert pos_max == h[ 'time_amplitude'], 'Wrong amplitude position found!' assert d[pos_max] == h['amplitude'], 'Wrong amplitude value found!' # Checking FHWM and FWTM: fractions = [0.1, 0.5] for f in fractions: amplitude = np.max(d) le = np.argwhere(d[:pos_max] <= amplitude * f) if len(le): le = le[-1, 0] m = d[le + 1] - d[le] le = le + 0.5 + (amplitude * f - d[le]) / m else: le = 0 re = np.argwhere(d[pos_max:] <= amplitude * f) if len(re) and re[0, 0] != 0: re = re[0, 0] + pos_max m = d[re] - d[re - 1] re = re + 0.5 + (amplitude * f - d[re]) / m else: re = len(d) if f == 0.5: left = 'left' fwxm = 'fwhm' else: left = 'low_left' fwxm = 'fwtm' assert math.isclose( le, h[left], rel_tol=10**-4, abs_tol=10**-4), f'Left edge does not match for fraction {f}' assert math.isclose(re - le, h[fwxm], rel_tol=10**-4, abs_tol=10**-4), f'FWHM does not match for {f}'
def test_hitlet_properties(hits_n_data): """ Function which tests refresh_hit_to_hitlets, hitlet_with_data_dtype, and hitlet_properties. :param hits_n_data: :return: """ hits, data = hits_n_data hits['time'] += 100 # Step 1.: Produce fake hits and convert them into hitlets: if len(hits) >= 1: nsamples = hits['length'].max() else: nsamples = 2 hitlets = np.zeros(len(hits), dtype=strax.hitlet_with_data_dtype(nsamples)) if len(hitlets): assert hitlets['data'].shape[1] >= 2, 'Data buffer is not at least 2 samples long.' strax.refresh_hit_to_hitlets(hits, hitlets) # Testing refresh_hit_to_hitlets for free: assert len(hits) == len(hitlets), 'Somehow hitlets and hits have different sizes' # Tetsing interval fields: dummy = np.zeros(0, dtype=strax.interval_dtype) for name in dummy.dtype.names: assert np.all(hitlets[name] == hits[name]), f'The entry of the field {name} did not match between hit and ' \ f'hitlets ' # Step 2.: Add to each hit(let) some data for ind, d in enumerate(data): h = hitlets[ind] h['data'][:h['length']] = d[:h['length']] strax.hitlet_properties(hitlets) # Step 4.: Apply tests. for ind, d in enumerate(data): h = hitlets[ind] d = d[:h['length']] pos_max = np.argmax(d) # Checking amplitude things: assert pos_max == h['time_amplitude'], 'Wrong amplitude position found!' assert d[pos_max] == h['amplitude'], 'Wrong amplitude value found!' # Checking FHWM and FWTM: fractions = [0.1, 0.5] for f in fractions: # Get field names for the correct test: if f == 0.5: left = 'left' fwxm = 'fwhm' else: left = 'low_left' fwxm = 'fwtm' amplitude = np.max(d) if np.all(d[0] == d) or np.all(d > amplitude*f): # If all samples are either the same or greater than required height FWXM is not defined: mes = 'All samples are the same or larger than require height.' assert np.isnan(h[left]), mes + f' Left edge for {f} should have been np.nan.' assert np.isnan(h[left]), mes + f' FWXM for X={f} should have been np.nan.' else: le = np.argwhere(d[:pos_max] <= amplitude * f) if len(le): le = le[-1, 0] m = d[le + 1] - d[le] le = le + 0.5 + (amplitude * f - d[le]) / m else: le = 0 re = np.argwhere(d[pos_max:] <= amplitude * f) if len(re) and re[0, 0] != 0: re = re[0, 0] + pos_max m = d[re] - d[re - 1] re = re + 0.5 + (amplitude * f - d[re]) / m else: re = len(d) assert math.isclose(le, h[left], rel_tol=10**-4, abs_tol=10**-4), f'Left edge does not match for fraction {f}' assert math.isclose(re - le, h[fwxm], rel_tol=10**-4, abs_tol=10**-4), f'FWHM does not match for {f}' # Step 5.: Unity test for not defined get_fhwm-cases: # This is a specific unity test for some edge-cases in which the full # width half maximum is not defined. odd_hitlets = np.zeros(3, dtype=strax.hitlet_with_data_dtype(10)) odd_hitlets[0]['data'][:5] = [2, 2, 3, 2, 2] odd_hitlets[0]['length'] = 5 odd_hitlets[1]['data'][:2] = [5, 5] odd_hitlets[1]['length'] = 2 odd_hitlets[2]['length'] = 3 for oh in odd_hitlets: res = strax.get_fwxm(oh) mes = (f'get_fxhm returned {res} for {oh["data"][:oh["length"]]}!' 'However, the FWHM is not defined and the return should be nan!' ) assert np.all(np.isnan(res)), mes