def get_skel_extremes(vox_size, energy_type, strict_vox_size, hitc): voxels = plf.voxelize_hits(hitc.hits, vox_size, strict_vox_size, energy_type) tracks = plf.make_track_graphs(voxels) df = pd.DataFrame(columns=[ 'event', 'trackID', 'energy', 'skel_extr1_x', 'skel_extr1_y', 'skel_extr1_z', 'skel_extr2_x', 'skel_extr2_y', 'skel_extr2_z' ]) if (len(voxels) == 0): return df vox_size_x = voxels[0].size[0] vox_size_y = voxels[0].size[1] vox_size_z = voxels[0].size[2] def get_track_energy(track): return sum([vox.Ehits for vox in track.nodes()]) #sort tracks in energy tracks = sorted(tracks, key=get_track_energy, reverse=True) track_hits = [] for c, t in enumerate(tracks, 0): tID = c energy = get_track_energy(t) extr1, extr2 = plf.find_extrema(t) extr1_pos = extr1.XYZ extr2_pos = extr2.XYZ list_of_vars = [ hitc.event, tID, energy, extr1_pos[0], extr1_pos[1], extr1_pos[2], extr2_pos[0], extr2_pos[1], extr2_pos[2] ] df.loc[c] = list_of_vars try: types_dict except NameError: types_dict = dict(zip(df.columns, [type(x) for x in list_of_vars])) #change dtype of columns to match type of variables df = df.apply(lambda x: x.astype(types_dict[x.name])) return df
voxels_dict['voxel_id'] = [1, 2, 3, 4, 5, 6, 7] voxels_dict['X'] = [30., 30., 60., 60., 60., 60., 20.] voxels_dict['Y'] = [30., 30., 60., 60., 60., 60., 20.] voxels_dict['Z'] = [30., 40., 30., 60., 70., 80., 80.] voxels_dict['E'] = [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.001] voxels_dict['negli'] = [False, False, False, False, False, False, True] voxels_df2 = pd.DataFrame(voxels_dict) voxels_df2.set_index(['event_id', 'voxel_id'], inplace=True) voxel_dimensions = (10., 10., 10.) ic_voxels = [Voxel(voxels_df2.iloc[i].X, voxels_df2.iloc[i].Y, voxels_df2.iloc[i].Z, voxels_df2.iloc[i].E, voxel_dimensions) \ for i in range(len(voxels_df2))] event_tracks = make_track_graphs(ic_voxels) def test_get_voxel_track_relations(): relations = [0, 0, 1, 2, 2, 2, np.nan] assert relations == get_voxel_track_relations(voxels_df2, event_tracks) def test_process_tracks(): track_Eth = 0.15 tracks_E = [0.3, 0.2] tracks_length = [20.0, 10.0] sorted_tracks = process_tracks(event_tracks, track_Eth) assert tracks_E[0] == pytest.approx(sorted_tracks[0][0])
def fanal_ana( det_name, # Detector name: 'new', 'next100', 'next500' event_type, # Event type: 'bb0nu', 'Tl208', 'Bi214' fwhm, # FWHM at Qbb voxel_size, # Voxel size (x, y, z) track_Eth, # Track energy threshold max_num_tracks, # Maximum number of tracks blob_radius, # Blob radius blob_Eth, # Blob energy threshold roi_Emin, # ROI minimum energy roi_Emax, # ROI maximum energy files_in, # Input files event_range, # Range of events to analyze: all, ... ?? file_out, # Output file compression, # Compression of output file: 'ZLIB1', 'ZLIB4', # 'ZLIB5', 'ZLIB9', 'BLOSC5', 'BLZ4HC5' verbosity_level): ### LOGGER logger = get_logger('FanalAna', verbosity_level) ### DETECTOR NAME det_name = getattr(DetName, det_name) ### PRINTING GENERAL INFO print( '\n***********************************************************************************' ) print('***** Detector: {}'.format(det_name.name)) print('***** Analizing {} events'.format(event_type)) print('***** Energy Resolution: {:.2f}% FWFM at Qbb'.format(fwhm / units.perCent)) print('***** Voxel Size: ({}, {}, {}) mm'.format(voxel_size[0] / units.mm, voxel_size[1] / units.mm, voxel_size[2] / units.mm)) print( '***********************************************************************************\n' ) print('* Track Eth: {:4.1f} keV Max Num Tracks: {}\n'.format( track_Eth / units.keV, max_num_tracks)) print('* Blob radius: {:.1f} mm Blob Eth: {:4.1f} keV\n'.format( blob_radius, blob_Eth / units.keV)) print('* ROI limits: [{:4.1f}, {:4.1f}] keV\n'.format( roi_Emin / units.keV, roi_Emax / units.keV)) ### INPUT RECONSTRUCTION FILE AND GROUP reco_group_name = get_reco_group_name(fwhm / units.perCent, voxel_size) print('* {} {} input reco file names:'.format(len(files_in), event_type)) for iFileName in files_in: print(' ', iFileName) print(' Reco group name: {}\n'.format(reco_group_name)) ### OUTPUT FILE, ITS GROUPS & ATTRIBUTES # Output analysis file oFile = tb.open_file(file_out, 'w', filters=tbl_filters(compression)) # Analysis group Name ana_group_name = get_ana_group_name(fwhm / units.perCent, voxel_size) oFile.create_group('/', 'FANALIC') oFile.create_group('/FANALIC', ana_group_name[9:]) print('* Output analysis file name:', file_out) print(' Ana group name: {}\n'.format(ana_group_name)) # Attributes oFile.set_node_attr(ana_group_name, 'input_reco_files', files_in) oFile.set_node_attr(ana_group_name, 'input_reco_group', reco_group_name) oFile.set_node_attr(ana_group_name, 'event_type', event_type) oFile.set_node_attr(ana_group_name, 'energy_resolution', fwhm / units.perCent) oFile.set_node_attr(ana_group_name, 'track_Eth', track_Eth) oFile.set_node_attr(ana_group_name, 'max_num_tracks', max_num_tracks) oFile.set_node_attr(ana_group_name, 'blob_radius', blob_radius) oFile.set_node_attr(ana_group_name, 'blob_Eth', blob_Eth) oFile.set_node_attr(ana_group_name, 'roi_Emin', roi_Emin) oFile.set_node_attr(ana_group_name, 'roi_Emax', roi_Emax) ### DATA TO STORE # Event counters simulated_events = 0 stored_events = 0 smE_filter_events = 0 fid_filter_events = 0 tracks_filter_events = 0 blobs_filter_events = 0 roi_filter_events = 0 analyzed_events = 0 toUpdate_events = 1 # Dictionaries for events & voxels data events_dict = get_events_ana_dict() voxels_dict = get_voxels_ana_dict() events_reco_df = pd.DataFrame() voxels_reco_df = pd.DataFrame() ### ANALYSIS PROCEDURE print('* Analyzing events ...\n') # Looping through all the input files for iFileName in files_in: # Updating reconstruction counters with tb.open_file(iFileName, mode='r') as reco_file: simulated_events += reco_file.get_node_attr( reco_group_name, 'simulated_events') stored_events += reco_file.get_node_attr(reco_group_name, 'stored_events') smE_filter_events += reco_file.get_node_attr( reco_group_name, 'smE_filter_events') fid_filter_events += reco_file.get_node_attr( reco_group_name, 'fid_filter_events') # Getting the events & voxels data from the reconstruction phase file_events = pd.read_hdf(iFileName, reco_group_name + '/events') file_voxels = pd.read_hdf(iFileName, reco_group_name + '/voxels') # Updating reconstruction dataframes events_reco_df = pd.concat([events_reco_df, file_events], axis=0) voxels_reco_df = pd.concat([voxels_reco_df, file_voxels], axis=0) print('* Processing {} ...'.format(iFileName)) ### Looping through all the events that passed the fiducial filter for event_number, event_df in file_events[ file_events.fid_filter].iterrows(): # Updating counter of analyzed events analyzed_events += 1 logger.info('Analyzing event Id: {0} ...'.format(event_number)) # Getting event data event_data = get_event_ana_data() event_data['event_id'] = event_number event_voxels = file_voxels.loc[event_number] num_event_voxels = len(event_voxels) num_event_voxels_negli = len(event_voxels[event_voxels.negli]) voxel_dimensions = (event_df.voxel_sizeX, event_df.voxel_sizeY, event_df.voxel_sizeZ) logger.info(' Total Voxels: {} Negli. Voxels: {} Voxels Size: ({:3.1f}, {:3.1f}, {:3.1f}) mm'\ .format(num_event_voxels, num_event_voxels_negli, voxel_dimensions[0], voxel_dimensions[1], voxel_dimensions[2])) # If there is any negligible Voxel, distribute its energy between its neighbours, # if not, all voxels maintain their previous energies if num_event_voxels_negli: event_voxels_newE = get_new_energies(event_voxels) else: event_voxels_newE = event_voxels.E.tolist() # Translate fanalIC voxels info to IC voxels to make tracks #ic_voxels = [Voxel(event_voxels.iloc[i].X, event_voxels.iloc[i].Y, event_voxels.iloc[i].Z, # event_voxels_newE[i], voxel_dimensions) for i in range(num_event_voxels)] ic_voxels = [] for i, voxel in event_voxels.iterrows(): ic_voxel = Voxel(voxel.X, voxel.Y, voxel.Z, event_voxels_newE[i], voxel_dimensions) ic_voxels.append(ic_voxel) # Make tracks event_tracks = make_track_graphs(ic_voxels) num_ini_tracks = len(event_tracks) logger.info(' Num initial tracks: {:2}'.format(num_ini_tracks)) # Appending to every voxel, the track it belongs to event_voxels_tracks = get_voxel_track_relations( event_voxels, event_tracks) # Appending ana-info to this event voxels extend_voxels_ana_dict(voxels_dict, event_number, event_voxels.index.tolist(), event_voxels_newE, event_voxels_tracks) # Processing tracks: Getting energies, sorting and filtering ... event_sorted_tracks = process_tracks(event_tracks, track_Eth) event_data['num_tracks'] = len(event_sorted_tracks) # Getting 3 hottest tracks info if event_data['num_tracks'] >= 1: event_data['track0_E'] = event_sorted_tracks[0][0] event_data['track0_length'] = event_sorted_tracks[0][1] event_data['track0_voxels'] = len( event_sorted_tracks[0][2].nodes()) if event_data['num_tracks'] >= 2: event_data['track1_E'] = event_sorted_tracks[1][0] event_data['track1_length'] = event_sorted_tracks[1][1] event_data['track1_voxels'] = len( event_sorted_tracks[1][2].nodes()) if event_data['num_tracks'] >= 3: event_data['track2_E'] = event_sorted_tracks[2][0] event_data['track2_length'] = event_sorted_tracks[2][1] event_data['track2_voxels'] = len( event_sorted_tracks[2][2].nodes()) # Applying the tracks filter consisting on: # 0 < num tracks < max_num_tracks # the track length must be longer than 2 times the blob_radius event_data['tracks_filter'] = ( (event_data['num_tracks'] > 0) & (event_data['num_tracks'] <= max_num_tracks) & (event_data['track0_length'] >= 2. * blob_radius)) # Verbosing logger.info(' Num final tracks: {:2} --> tracks_filter: {}' \ .format(event_data['num_tracks'], event_data['tracks_filter'])) ### For those events passing the tracks filter: if event_data['tracks_filter']: # Getting the blob energies of the track with highest energy event_data['blob1_E'], event_data['blob2_E'] = \ blob_energies(event_sorted_tracks[0][2], blob_radius) # Applying the blobs filter event_data['blobs_filter'] = (event_data['blob2_E'] > blob_Eth) # Verbosing logger.info(' Blob 1 energy: {:4.1f} keV Blob 2 energy: {:4.1f} keV --> Blobs filter: {}'\ .format(event_data['blob1_E']/units.keV, event_data['blob2_E']/units.keV, event_data['blobs_filter'])) ### For those events passing the blobs filter: if event_data['blobs_filter']: # Getting the total event smeared energy event_smE = file_events.loc[event_number].smE # Applying the ROI filter event_data['roi_filter'] = ((event_smE >= roi_Emin) & (event_smE <= roi_Emax)) # Verbosing logger.info(' Event energy: {:6.1f} keV --> ROI filter: {}'\ .format(event_smE / units.keV, event_data['roi_filter'])) # Storing event_data extend_events_ana_dict(events_dict, event_data) # Verbosing if (not (analyzed_events % toUpdate_events)): print('* Num analyzed events: {}'.format(analyzed_events)) if (analyzed_events == (10 * toUpdate_events)): toUpdate_events *= 10 ### STORING ANALYSIS DATA print('* Total analyzed events: {}'.format(analyzed_events)) # Storing events and voxels dataframes print('\n* Storing data in the output file ...\n {}\n'.format(file_out)) store_events_ana_dict(file_out, ana_group_name, events_reco_df, events_dict) store_voxels_ana_dict(file_out, ana_group_name, voxels_reco_df, voxels_dict) # Storing event counters as attributes tracks_filter_events = sum(events_dict['tracks_filter']) blobs_filter_events = sum(events_dict['blobs_filter']) roi_filter_events = sum(events_dict['roi_filter']) store_events_ana_counters(oFile, ana_group_name, simulated_events, stored_events, smE_filter_events, fid_filter_events, tracks_filter_events, blobs_filter_events, roi_filter_events) ### Ending ... oFile.close() print('* Analysis done !!\n') print('''* Event counters: Simulated events: {0:9} Stored events: {1:9} smE_filter events: {2:9} fid_filter events: {3:9} tracks_filter events: {4:9} blobs_filter events: {5:9} roi_filter events: {6:9}'''.format(simulated_events, stored_events, smE_filter_events, fid_filter_events, tracks_filter_events, blobs_filter_events, roi_filter_events))
df = pd.read_csv("data_1000keV_local.csv", usecols=["event_number", "x", "y", "z"]) mask = df.event_number < 20 df = df[mask] trk_lengths = [] for i in range(df.event_number.max() + 1): #df_i = df[df.event_number == i] hit_list = [ BHit(row.x, row.y, row.z, 1.) for indx, row in df[df.event_number == i].iterrows() ] voxels = plf.voxelize_hits(hit_list, np.array((1., 1., 1.))) tracks = plf.make_track_graphs(voxels) all_lengths = [] for j in np.arange(len(tracks)): all_lengths.append(plf.length(tracks[j])) trk_lengths.append(max(all_lengths)) plt.figure(0) plt.hist(trk_lengths, range=(0, 200), bins=70) plt.xlabel("Track length (mm)") plt.savefig( "/data5/users/miryam/temp/voxel/img/voxel_track_length_1000keV_local_20events.pdf" ) plt.close(0)
def create_tracks_with_skel_extremes(vox_size, energy_type, strict_vox_size, blob_radius, df_extr, hitc): voxels = plf.voxelize_hits(hitc.hits, vox_size, strict_vox_size, energy_type) tracks = plf.make_track_graphs(voxels) df = pd.DataFrame(columns=[ 'event', 'trackID', 'energy', 'length', 'numb_of_voxels', 'numb_of_hits', 'numb_of_tracks', 'x_min', 'y_min', 'z_min', 'x_max', 'y_max', 'z_max', 'r_max', 'x_ave', 'y_ave', 'z_ave', 'extreme1_x', 'extreme1_y', 'extreme1_z', 'extreme2_x', 'extreme2_y', 'extreme2_z', 'blob1_x', 'blob1_y', 'blob1_z', 'blob2_x', 'blob2_y', 'blob2_z', 'eblob1', 'eblob2', 'ovlp_blob_energy', 'vox_size_x', 'vox_size_y', 'vox_size_z' ]) if (len(voxels) == 0): return df vox_size_x = voxels[0].size[0] vox_size_y = voxels[0].size[1] vox_size_z = voxels[0].size[2] def get_track_energy(track): return sum([vox.Ehits for vox in track.nodes()]) #sort tracks in energy tracks = sorted(tracks, key=get_track_energy, reverse=True) track_hits = [] for c, t in enumerate(tracks, 0): tID = c energy = get_track_energy(t) length = plf.length(t) numb_of_hits = len([h for vox in t.nodes() for h in vox.hits]) numb_of_voxels = len(t.nodes()) numb_of_tracks = len(tracks) min_x = min([h.X for v in t.nodes() for h in v.hits]) max_x = max([h.X for v in t.nodes() for h in v.hits]) min_y = min([h.Y for v in t.nodes() for h in v.hits]) max_y = max([h.Y for v in t.nodes() for h in v.hits]) min_z = min([h.Z for v in t.nodes() for h in v.hits]) max_z = max([h.Z for v in t.nodes() for h in v.hits]) max_r = max([ np.sqrt(h.X * h.X + h.Y * h.Y) for v in t.nodes() for h in v.hits ]) pos = [h.pos for v in t.nodes() for h in v.hits] e = [getattr(h, energy_type.value) for v in t.nodes() for h in v.hits] ave_pos = np.average(pos, weights=e, axis=0) # classic paolina extremes extr1, extr2 = plf.find_extrema(t) extr1_pos = extr1.XYZ extr2_pos = extr2.XYZ t_extr = df_extr[df_extr.trackID == tID] if len(t_extr) == 0: blob_pos1 = np.array([1.e6, 1.e6, 1.e6]) blob_pos2 = np.array([1.e6, 1.e6, 1.e6]) eblob1 = -1 eblob2 = -1 overlap = -1 else: blob_pos1 = np.array([ t_extr.skel_extr1_x.values[0], t_extr.skel_extr1_y.values[0], t_extr.skel_extr1_z.values[0] ]) blob_pos2 = np.array([ t_extr.skel_extr2_x.values[0], t_extr.skel_extr2_y.values[0], t_extr.skel_extr2_z.values[0] ]) e_blob1, e_blob2, hits_blob1, hits_blob2, blob_pos1, blob_pos2 = blob_energies_hits( t, blob_radius, blob_pos1, blob_pos2) overlap = sum( [h.E for h in set(hits_blob1).intersection(set(hits_blob2))]) list_of_vars = [ hitc.event, tID, energy, length, numb_of_voxels, numb_of_hits, numb_of_tracks, min_x, min_y, min_z, max_x, max_y, max_z, max_r, ave_pos[0], ave_pos[1], ave_pos[2], extr1_pos[0], extr1_pos[1], extr1_pos[2], extr2_pos[0], extr2_pos[1], extr2_pos[2], blob_pos1[0], blob_pos1[1], blob_pos1[2], blob_pos2[0], blob_pos2[1], blob_pos2[2], e_blob1, e_blob2, overlap, vox_size_x, vox_size_y, vox_size_z ] df.loc[c] = list_of_vars try: types_dict except NameError: types_dict = dict(zip(df.columns, [type(x) for x in list_of_vars])) #change dtype of columns to match type of variables df = df.apply(lambda x: x.astype(types_dict[x.name])) return df
def fanal_ana(det_name, # Detector name: 'new', 'next100', 'next500' event_type, # Event type: 'bb0nu', 'Tl208', 'Bi214' fwhm, # FWHM at Qbb spatial_def, # Spatial definition: 'low', 'high' voxel_Eth, # Voxel energy threshold track_Eth, # Track energy threshold max_num_tracks, # Maximum number of tracks blob_radius, # Blob radius blob_Eth, # Blob energy threshold roi_Emin, # ROI minimum energy roi_Emax, # ROI maximum energy files_in, # Input files event_range, # Range of events to analyze: all, ... ?? file_out, # Output file compression, # Compression of output file: 'ZLIB1', 'ZLIB4', # 'ZLIB5', 'ZLIB9', 'BLOSC5', 'BLZ4HC5' verbosity_level): ### LOGGER logger = get_logger('FanalAna', verbosity_level) ### DETECTOR NAME det_name = getattr(DetName, det_name) ### SPATIAL DEFINITION spatial_def = getattr(SpatialDef, spatial_def) ### PRINTING GENERAL INFO print('\n***********************************************************************************') print('***** Detector: {}'.format(det_name.name)) print('***** Analizing {} events'.format(event_type)) print('***** Energy Resolution: {:.2f}% FWFM at Qbb'.format(fwhm / units.perCent)) print('***** Spatial definition: {}'.format(spatial_def.name)) print('***********************************************************************************\n') print('* Voxel Eth: {:4.1f} keV Track Eth: {:4.1f} keV Max Num Tracks: {}\n' .format(voxel_Eth/units.keV, track_Eth/units.keV, max_num_tracks)) print('* Blob radius: {:.1f} mm Blob Eth: {:4.1f} keV\n' .format(blob_radius, blob_Eth / units.keV)) print('* ROI limits: [{:4.1f}, {:4.1f}] keV\n' .format(roi_Emin/units.keV, roi_Emax/units.keV)) ### INPUT RECONSTRUCTION FILE AND GROUP reco_group_name = get_reco_group_name(fwhm/units.perCent, spatial_def) print('* Input reco file name:', files_in) print(' Reco group name: {}\n'.format(reco_group_name)) ### OUTPUT FILE, ITS GROUPS & ATTRIBUTES # Output analysis file oFile = tb.open_file(file_out, 'w', filters=tbl_filters(compression)) # Analysis group Name ana_group_name = get_ana_group_name(fwhm/units.perCent, spatial_def) oFile.create_group('/', 'FANALIC') oFile.create_group('/FANALIC', ana_group_name[9:]) print('* Output analysis file name:', file_out) print(' Ana group name: {}\n'.format(ana_group_name)) # Attributes oFile.set_node_attr(ana_group_name, 'input_reco_file', files_in[0]) oFile.set_node_attr(ana_group_name, 'input_reco_group', reco_group_name) oFile.set_node_attr(ana_group_name, 'event_type', event_type) oFile.set_node_attr(ana_group_name, 'energy_resolution', fwhm / units.perCent) oFile.set_node_attr(ana_group_name, 'voxel_Eth', voxel_Eth) oFile.set_node_attr(ana_group_name, 'track_Eth', track_Eth) oFile.set_node_attr(ana_group_name, 'max_num_tracks', max_num_tracks) oFile.set_node_attr(ana_group_name, 'blob_radius', blob_radius) oFile.set_node_attr(ana_group_name, 'blob_Eth', blob_Eth) oFile.set_node_attr(ana_group_name, 'roi_Emin', roi_Emin) oFile.set_node_attr(ana_group_name, 'roi_Emax', roi_Emax) ### DATA TO STORE # Dictionaries for events & voxels data events_dict = get_events_ana_dict() voxels_dict = get_voxels_ana_dict() ### ANALYSIS PROCEDURE # Getting the events & voxels data from the reconstruction phase # This is the option a little bit slower that requires less memory ... (TO BE CHECKED!!) # event_numbers_toAnalize = pd.read_hdf(files_in[0], reco_group_name + '/events', # where=['fid_filter = True']).index # And this is the fastest option requiring more memory events_df = pd.read_hdf(files_in[0], reco_group_name + '/events') voxels_df = pd.read_hdf(files_in[0], reco_group_name + '/voxels') # Identifying as negligible all the voxels with energy lower than threshold voxels_df['negli'] = voxels_df.E < voxel_Eth print('* Total Voxels in File: {0} Negligible Voxels (below {1:3.1f} keV): {2}\n' .format(len(voxels_df), voxel_Eth / units.keV, len(voxels_df[voxels_df.negli == True]))) # Analyzing only the fiducial events ... print('* Analyzing events ...\n') # Counter of analyzed events for verbosing pourpouses num_analyzed_events = 0 # Looping through all the events that passed the fiducial filter for event_id in events_df[events_df.fid_filter].index: # Updating counter of analyzed events num_analyzed_events += 1 if not int(str(num_analyzed_events)[-int(math.log10(num_analyzed_events)):]): print('* Num analyzed events: {}'.format(num_analyzed_events)) # Verbosing logger.info('Analyzing event Id: {0} ...'.format(event_id)) # Getting the voxels of current event and their sizes event_voxels = voxels_df[voxels_df.event_id == event_id] num_event_voxels = len(event_voxels) num_event_voxels_negli = len(event_voxels[event_voxels.negli == True]) event_data = events_df.loc[event_id] voxel_dimensions = (event_data.voxel_sizeX, event_data.voxel_sizeY, event_data.voxel_sizeZ) logger.info(' Total Voxels: {} Negli. Voxels: {} Voxels Size: ({:3.1f}, {:3.1f}, {:3.1f}) mm' .format(num_event_voxels, num_event_voxels_negli, voxel_dimensions[0], voxel_dimensions[1], voxel_dimensions[2])) # If there is any negligible Voxel, # distribute its energy between its neighbours, # if not, all voxels maintain their previous energies if num_event_voxels_negli: event_voxels_newE = get_new_energies(event_voxels) else: event_voxels_newE = event_voxels.E.tolist() # Translate fanalIC voxels info to IC voxels to make tracks ic_voxels = [Voxel(event_voxels.iloc[i].X, event_voxels.iloc[i].Y, event_voxels.iloc[i].Z, event_voxels_newE[i], voxel_dimensions) for i in range(num_event_voxels)] # Make tracks event_tracks = make_track_graphs(ic_voxels) num_event_tracks = len(event_tracks) logger.info(' Num initial tracks: {:2}'.format(num_event_tracks)) # Appending to every voxel, the track it belongs to event_voxels_tracks = get_voxel_track_relations(event_voxels, event_tracks) # Appending info of this event voxels extend_voxels_ana_data(voxels_dict, event_voxels.index, event_voxels_newE, event_voxels_tracks) # Processing tracks: Getting energies, sorting and filtering ... event_sorted_tracks = process_tracks(event_tracks, track_Eth) num_event_tracks = len(event_sorted_tracks) # Storing 3 hottest track info if num_event_tracks >= 1: track0_E = event_sorted_tracks[0][0] track0_voxels = len(event_sorted_tracks[0][1].nodes()) track0_length = track_length(event_sorted_tracks[0][1]) else: track0_E = track0_voxels = track0_length = np.nan if num_event_tracks >= 2: track1_E = event_sorted_tracks[1][0] track1_voxels = len(event_sorted_tracks[1][1].nodes()) track1_length = track_length(event_sorted_tracks[1][1]) else: track1_E = track1_voxels = track1_length = np.nan if num_event_tracks >= 3: track2_E = event_sorted_tracks[2][0] track2_voxels = len(event_sorted_tracks[2][1].nodes()) track2_length = track_length(event_sorted_tracks[2][1]) else: track2_E = track2_voxels = track2_length = np.nan # Applying the tracks filter tracks_filter = ((num_event_tracks > 0) & (num_event_tracks <= max_num_tracks)) # Verbosing logger.info(' Num final tracks: {:2} --> tracks_filter: {}' .format(num_event_tracks, tracks_filter)) # For those events NOT passing the tracks filter: # Storing data of NON tracks_filter vents if not tracks_filter: extend_events_ana_data(events_dict, event_id, num_event_tracks, track0_E, track0_voxels, track0_length, track1_E, track1_voxels, track1_length, track2_E, track2_voxels, track2_length, tracks_filter) # Only for those events passing the tracks filter: else: # Getting the blob energies of the track with highest energy blobs_E = blob_energies(event_sorted_tracks[0][1], blob_radius) blob1_E = blobs_E[1] blob2_E = blobs_E[0] # Applying the blobs filter blobs_filter = (blob2_E > blob_Eth) # Verbosing logger.info(' Blob 1 energy: {:4.1f} keV Blob 2 energy: {:4.1f} keV --> Blobs filter: {}' .format(blob1_E/units.keV, blob2_E/units.keV, blobs_filter)) # For those events NOT passing the blobs filter: # Storing data of NON blobs_filter vents if not blobs_filter: extend_events_ana_data(events_dict, event_id, num_event_tracks, track0_E, track0_voxels, track0_length, track1_E, track1_voxels, track1_length, track2_E, track2_voxels, track2_length, tracks_filter, blob1_E = blob1_E, blob2_E = blob2_E, blobs_filter = blobs_filter) # Only for those events passing the blobs filter: else: # Getting the total event smeared energy event_smE = events_df.loc[event_id].smE # Applying the ROI filter roi_filter = ((event_smE >= roi_Emin) & (event_smE <= roi_Emax)) # Verbosing logger.info(' Event energy: {:6.1f} keV --> ROI filter: {}' .format(event_smE / units.keV, roi_filter)) # Storing all the events (as this is the last filter) extend_events_ana_data(events_dict, event_id, num_event_tracks, track0_E, track0_voxels, track0_length, track1_E, track1_voxels, track1_length, track2_E, track2_voxels, track2_length, tracks_filter, blob1_E = blob1_E, blob2_E = blob2_E, blobs_filter = blobs_filter, roi_filter = roi_filter) ### STORING DATA # Storing events and voxels dataframes print('\n* Storing data in the output file ...\n {}\n'.format(file_out)) store_events_ana_data(file_out, ana_group_name, events_df, events_dict) store_voxels_ana_data(file_out, ana_group_name, voxels_df, voxels_dict) # Storing event counters as attributes tracks_filter_events, blobs_filter_events, roi_filter_events = \ store_events_ana_counters(oFile, ana_group_name, events_df) ### Ending ... oFile.close() print('* Analysis done !!\n') # Printing analysis numbers with tb.open_file(files_in[0], mode='r') as iFile: simulated_events = iFile.get_node_attr(reco_group_name, 'simulated_events') stored_events = iFile.get_node_attr(reco_group_name, 'stored_events') smE_filter_events = iFile.get_node_attr(reco_group_name, 'smE_filter_events') fid_filter_events = iFile.get_node_attr(reco_group_name, 'fid_filter_events') print('''* Event counters: Simulated events: {0:9} Stored events: {1:9} smE_filter events: {2:9} fid_filter events: {3:9} tracks_filter events: {4:9} blobs_filter events: {5:9} roi_filter events: {6:9}\n''' .format(simulated_events, stored_events, smE_filter_events, fid_filter_events, tracks_filter_events, blobs_filter_events, roi_filter_events))
def create_extract_track_blob_info(hitc): df = pd.DataFrame(columns=list(types_dict_tracks.keys())) if len(hitc.hits) > max_num_hits: return df, hitc, True #track_hits is a new Hitcollection object that contains hits belonging to tracks, and hits that couldnt be corrected track_hitc = evm.HitCollection(hitc.event, hitc.time) out_of_map = np.any(np.isnan([h.Ep for h in hitc.hits])) if out_of_map: #add nan hits to track_hits, the track_id will be -1 track_hitc.hits.extend([h for h in hitc.hits if np.isnan(h.Ep)]) hits_without_nan = [h for h in hitc.hits if np.isfinite(h.Ep)] #create new Hitcollection object but keep the name hitc hitc = evm.HitCollection(hitc.event, hitc.time) hitc.hits = hits_without_nan if len(hitc.hits) > 0: voxels = plf.voxelize_hits(hitc.hits, vox_size, strict_vox_size, evm.HitEnergy.Ep) (mod_voxels, dropped_voxels) = plf.drop_end_point_voxels( voxels, energy_threshold, min_voxels) tracks = plf.make_track_graphs(mod_voxels) for v in dropped_voxels: track_hitc.hits.extend(v.hits) vox_size_x = voxels[0].size[0] vox_size_y = voxels[0].size[1] vox_size_z = voxels[0].size[2] del (voxels) #sort tracks in energy tracks = sorted(tracks, key=plf.get_track_energy, reverse=True) track_hits = [] for c, t in enumerate(tracks, 0): tID = c energy = plf.get_track_energy(t) length = plf.length(t) numb_of_hits = len([h for vox in t.nodes() for h in vox.hits]) numb_of_voxels = len(t.nodes()) numb_of_tracks = len(tracks) pos = [h.pos for v in t.nodes() for h in v.hits] x, y, z = map(np.array, zip(*pos)) r = np.sqrt(x**2 + y**2) e = [h.Ep for v in t.nodes() for h in v.hits] ave_pos = np.average(pos, weights=e, axis=0) ave_r = np.average(r, weights=e, axis=0) extr1, extr2 = plf.find_extrema(t) extr1_pos = extr1.XYZ extr2_pos = extr2.XYZ blob_pos1, blob_pos2 = plf.blob_centres(t, blob_radius) e_blob1, e_blob2, hits_blob1, hits_blob2 = plf.blob_energies_and_hits( t, blob_radius) overlap = float( sum(h.Ep for h in set(hits_blob1).intersection( set(hits_blob2)))) list_of_vars = [ hitc.event, tID, energy, length, numb_of_voxels, numb_of_hits, numb_of_tracks, min(x), min(y), min(z), min(r), max(x), max(y), max(z), max(r), *ave_pos, ave_r, *extr1_pos, *extr2_pos, *blob_pos1, *blob_pos2, e_blob1, e_blob2, overlap, vox_size_x, vox_size_y, vox_size_z ] df.loc[c] = list_of_vars for vox in t.nodes(): for hit in vox.hits: hit.track_id = tID track_hits.append(hit) #change dtype of columns to match type of variables df = df.apply(lambda x: x.astype(types_dict_tracks[x.name])) track_hitc.hits.extend(track_hits) return df, mod_voxels, track_hitc, out_of_map
def create_extract_track_blob_info(hitc): voxels = plf.voxelize_hits(hitc.hits, vox_size, strict_vox_size, energy_type) tracks = plf.make_track_graphs(voxels) df = pd.DataFrame(columns=[ 'event', 'trackID', 'energy', 'length', 'numb_of_voxels', 'numb_of_hits', 'numb_of_tracks', 'x_min', 'y_min', 'z_min', 'x_max', 'y_max', 'z_max', 'r_max', 'x_ave', 'y_ave', 'z_ave', 'extreme1_x', 'extreme1_y', 'extreme1_z', 'extreme2_x', 'extreme2_y', 'extreme2_z', 'blob1_x', 'blob1_y', 'blob1_z', 'blob2_x', 'blob2_y', 'blob2_z', 'eblob1', 'eblob2', 'ovlp_blob_energy', 'vox_size_x', 'vox_size_y', 'vox_size_z' ]) if (len(voxels) == 0): return df, None vox_size_x = voxels[0].size[0] vox_size_y = voxels[0].size[1] vox_size_z = voxels[0].size[2] def get_track_energy(track): return sum([vox.Ehits for vox in track.nodes()]) #sort tracks in energy tracks = sorted(tracks, key=get_track_energy, reverse=True) track_hits = [] for c, t in enumerate(tracks, 0): tID = c energy = get_track_energy(t) length = plf.length(t) numb_of_hits = len([h for vox in t.nodes() for h in vox.hits]) numb_of_voxels = len(t.nodes()) numb_of_tracks = len(tracks) min_x = min([h.X for v in t.nodes() for h in v.hits]) max_x = max([h.X for v in t.nodes() for h in v.hits]) min_y = min([h.Y for v in t.nodes() for h in v.hits]) max_y = max([h.Y for v in t.nodes() for h in v.hits]) min_z = min([h.Z for v in t.nodes() for h in v.hits]) max_z = max([h.Z for v in t.nodes() for h in v.hits]) max_r = max([ np.sqrt(h.X * h.X + h.Y * h.Y) for v in t.nodes() for h in v.hits ]) pos = [h.pos for v in t.nodes() for h in v.hits] e = [ getattr(h, energy_type.value) for v in t.nodes() for h in v.hits ] ave_pos = np.average(pos, weights=e, axis=0) extr1, extr2 = plf.find_extrema(t) extr1_pos = extr1.XYZ extr2_pos = extr2.XYZ blob_pos1, blob_pos2 = plf.blob_centres(t, blob_radius) e_blob1, e_blob2, hits_blob1, hits_blob2 = plf.blob_energies_and_hits( t, blob_radius) overlap = False overlap = sum( [h.E for h in set(hits_blob1).intersection(hits_blob2)]) list_of_vars = [ hitc.event, tID, energy, length, numb_of_voxels, numb_of_hits, numb_of_tracks, min_x, min_y, min_z, max_x, max_y, max_z, max_r, ave_pos[0], ave_pos[1], ave_pos[2], extr1_pos[0], extr1_pos[1], extr1_pos[2], extr2_pos[0], extr2_pos[1], extr2_pos[2], blob_pos1[0], blob_pos1[1], blob_pos1[2], blob_pos2[0], blob_pos2[1], blob_pos2[2], e_blob1, e_blob2, overlap, vox_size_x, vox_size_y, vox_size_z ] df.loc[c] = list_of_vars try: types_dict except NameError: types_dict = dict( zip(df.columns, [type(x) for x in list_of_vars])) for vox in t.nodes(): for hit in vox.hits: hit.track_id = tID track_hits.append(hit) track_hitc = evm.HitCollection(hitc.event, hitc.time) track_hitc.hits = track_hits #change dtype of columns to match type of variables df = df.apply(lambda x: x.astype(types_dict[x.name])) return df, track_hitc
events_in += len(hits_evt) for nevt, hitc in hits_evt.items(): if bad_event[nevt]: not_fid += 1 continue tot_e = sum(h.E for h in hitc) voxels = plf.voxelize_hits(hitc, vox_size) mod_voxels = plf.drop_end_point_voxels(voxels, voxel_cut, min_vxls=3) ### Make tracks with the new voxels trks = plf.make_track_graphs(mod_voxels) ### Is it a e+e- events? positron = False for _, particle in p_dict[nevt].items(): if (particle.name == 'e+') & (len(particle.hits) > 0): positron = True for c, t in enumerate(trks, 0): etrk = sum(vox.E for vox in t.nodes()) n_hits = sum(len(v.hits) for v in t.nodes()) extr1, extr2 = plf.find_extrema(t) e_blob1, e_blob2, hits_blob1, hits_blob2, pos1, pos2 = plf.blob_energies_hits_and_centres( t, blob_radius)
def analyze_bb_event_ic( detector: Detector, event_id: int, params: BBAnalysisParams, fiducial_checker: Callable, event_mcParts: pd.DataFrame, event_mcHits: pd.DataFrame) -> Tuple[Event, TrackList, VoxelList]: """ It assess the global acceptance factor after fiducial, topology and ROI cuts based on the paolina functions implemented into IC. """ # Data to be filled event_data = Event() tracks_data = TrackList() voxels_data = VoxelList() # Storing basic MC data event_data.event_id = event_id event_data.num_mcParts = len(event_mcParts) event_data.num_mcHits = len(event_mcHits) logger.info(f"Num mcParticles: {event_data.num_mcParts:3} " + \ f"Num mcHits: {event_data.num_mcHits:3} ") # Processing MC data event_data.mc_energy, event_data.mc_filter = \ check_mc_data(event_mcHits, params.buffer_Eth, params.e_min, params.e_max) if not event_data.mc_filter: return event_data, tracks_data, voxels_data ### Continue analysis of events passing the mc_filter ### # Reconstruct hits active_mcHits = event_mcHits[event_mcHits.label == 'ACTIVE'] recons_hits = reconstruct_hits(detector, active_mcHits, event_data.mc_energy, params.fwhm, params.trans_diff, params.long_diff) # Event smeared energy event_data.sm_energy = recons_hits.energy.sum() event_data.energy_filter = (params.e_min <= event_data.sm_energy <= params.e_max) logger.info(f"smE: {event_data.sm_energy/units.keV:.1f} keV " + \ f"ENERGY filter: {event_data.energy_filter}") if not event_data.energy_filter: return event_data, tracks_data, voxels_data ### Continue analysis of events passing the energy_filter ### # Creating the IChits from reconstructed hits ic_hits = recons_hits.apply(lambda hit: \ MCHit((hit.x, hit.y, hit.z), hit.time, hit.energy, 'ACTIVE'), axis=1).tolist() # Voxelizing using the ic_hits ... ic_voxels = voxelize_hits( ic_hits, [params.voxel_size_x, params.voxel_size_y, params.voxel_size_z], params.strict_voxel_size) # Cleaning voxels with energy < voxel_Eth ic_voxels = clean_voxels(ic_voxels, params.voxel_Eth) event_data.num_voxels = len(ic_voxels) eff_voxel_size = ic_voxels[0].size event_data.voxel_size_x = eff_voxel_size[0] event_data.voxel_size_y = eff_voxel_size[1] event_data.voxel_size_z = eff_voxel_size[2] logger.info( f"Num Voxels: {event_data.num_voxels:3} of size: {eff_voxel_size} mm") # Check fiduciality event_data.veto_energy, event_data.fiduc_filter = \ check_event_fiduciality(fiducial_checker, ic_voxels, params.veto_Eth) logger.info(f"Veto_E: {event_data.veto_energy/units.keV:.1f} keV " + \ f"FIDUC filter: {event_data.fiduc_filter}") if not event_data.fiduc_filter: # Storing voxels without track-id info for voxel_id in range(len(ic_voxels)): voxels_data.add( Voxel.from_icVoxel(event_id, -1, voxel_id, ic_voxels[voxel_id])) logger.debug(voxels_data) return event_data, tracks_data, voxels_data ### Continue analysis of events passing the fiduc_filter ### # Make tracks ic_tracks = make_track_graphs(ic_voxels) # Storing tracks from ic_tracks for track_id in range(len(ic_tracks)): ic_track = ic_tracks[track_id] tracks_data.add(Track.from_icTrack(event_id, track_id, ic_track)) # Storing voxels from ic_voxels ic_voxels = list(ic_track.nodes()) for voxel_id in range(len(ic_voxels)): voxels_data.add( Voxel.from_icVoxel(event_id, track_id, voxel_id, ic_voxels[voxel_id])) logger.debug(voxels_data) event_data.num_tracks = tracks_data.len() event_data.track_filter = ( (event_data.num_tracks > 0) & (event_data.num_tracks <= params.max_num_tracks)) logger.info(f"Num tracks: {event_data.num_tracks:3} ->" + \ f" TRACK filter: {event_data.track_filter}") if not event_data.track_filter: return event_data, tracks_data, voxels_data ### Continue analysis of events passing the track_filter ### the_track = tracks_data.tracks[0] # Getting & Storing Blobs info blob1_energy, blob2_energy, blob1_hits, blob2_hits, blob1_pos, blob2_pos = \ blob_energies_hits_and_centres(ic_tracks[0], params.blob_radius) blob1_pos, blob2_pos = XYZ.from_array(blob1_pos), XYZ.from_array(blob2_pos) the_track.blob1_energy, the_track.blob1_num_hits = blob1_energy, len( blob1_hits) the_track.blob1_x, the_track.blob1_y, the_track.blob1_z = \ blob1_pos.x, blob1_pos.y, blob1_pos.z the_track.blob2_energy, the_track.blob2_num_hits = blob2_energy, len( blob2_hits) the_track.blob2_x, the_track.blob2_y, the_track.blob2_z = \ blob2_pos.x, blob2_pos.y, blob2_pos.z the_track.ovlp_energy = \ float(sum(hit.E for hit in set(blob1_hits).intersection(set(blob2_hits)))) # Getting & Storing True extrema info ext1, ext2 = get_true_extrema(event_mcParts, params.event_type) ext1, ext2 = order_true_extrema(ext1, ext2, blob1_pos, blob2_pos) the_track.t_ext1_x, the_track.t_ext1_y, the_track.t_ext1_z = ext1.x, ext1.y, ext1.z the_track.t_ext2_x, the_track.t_ext2_y, the_track.t_ext2_z = ext2.x, ext2.y, ext2.z # Storing Track info in event data event_data.track_length = the_track.length event_data.blob1_energy, event_data.blob2_energy = blob1_energy, blob2_energy logger.info(tracks_data) # Applying the blob filter event_data.blob_filter = ((event_data.blob2_energy > params.blob_Eth) & (the_track.ovlp_energy == 0.)) logger.info(f"Blob 1 energy: {event_data.blob1_energy/units.keV:4.1f} keV " + \ f" Blob 2 energy: {event_data.blob2_energy/units.keV:4.1f} keV" + \ f" Overlap: {the_track.ovlp_energy/units.keV:4.1f} keV" + \ f" -> BLOB filter: {event_data.blob_filter}") if not event_data.blob_filter: return event_data, tracks_data, voxels_data ### Continue analysis of events passing the blob_filter ### # Applying the ROI filter event_data.roi_filter = ((event_data.sm_energy >= params.roi_Emin) & (event_data.sm_energy <= params.roi_Emax)) logger.info(f"Event energy: {event_data.sm_energy/units.keV:6.1f} keV" + \ f" -> ROI filter: {event_data.roi_filter}") return event_data, tracks_data, voxels_data