def generate(inputFile, paramFile, outFile, seed=1, nEvents=None): firstEvent = 0 dy = 10. vessel_design = 5 shield_design = 8 mcEngine = 'TGeant4' sameSeed = seed theSeed = 1 phiRandom = False # only relevant for muon background generator followMuon = True # only transport muons for a fast muon only background print('FairShip setup to produce', nEvents, 'events') r.gRandom.SetSeed(theSeed) ship_geo = ConfigRegistry.loadpy('$FAIRSHIP/geometry/geometry_config.py', Yheight=dy, tankDesign=vessel_design, muShieldDesign=shield_design, muShieldGeo=paramFile) run = r.FairRunSim() run.SetName(mcEngine) # Transport engine run.SetOutputFile(outFile) # Output file # user configuration file default g4Config.C run.SetUserConfig('g4Config.C') modules = shipDet_conf.configure(run, ship_geo) primGen = r.FairPrimaryGenerator() primGen.SetTarget(ship_geo.target.z0 + 50 * u.m, 0.) MuonBackgen = r.MuonBackGenerator() MuonBackgen.Init(inputFile, firstEvent, phiRandom) MuonBackgen.SetSmearBeam(3 * u.cm) # beam size mimicking spiral if sameSeed: MuonBackgen.SetSameSeed(sameSeed) primGen.AddGenerator(MuonBackgen) nEvents = MuonBackgen.GetNevents() - 1 print('Process ', nEvents, ' from input file, with Phi random=', phiRandom) if followMuon: modules['Veto'].SetFastMuon() run.SetGenerator(primGen) run.SetStoreTraj(r.kFALSE) run.Init() print('Initialised run.') geomGeant4.addVMCFields(ship_geo, '', True) print('Start run of {} events.'.format(nEvents)) run.Run(nEvents) print('Finished simulation of {} events.'.format(nEvents))
def run_ship(self, phiRandom=False, followMuon=True, n_events=10, first_event=0): """ phiRandom = False # only relevant for muon background generator followMuon = True # only transport muons for a fast muon only background """ r.gErrorIgnoreLevel = r.kWarning r.gSystem.Load('libpythia8') print ('FairShip setup to produce', n_events, 'events') r.gRandom.SetSeed(self.theSeed) ship_geo = ConfigRegistry.loadpy( '$FAIRSHIP/geometry/geometry_config.py', Yheight=self.dy, tankDesign=self.vessel_design, muShieldDesign=self.shield_design, muShieldGeo=self.shield_geo_file) run = r.FairRunSim() run.SetName(self.mcEngine) # Transport engine run.SetOutputFile(self.output_file) # Output file # user configuration file default g4Config.C run.SetUserConfig('g4Config.C') modules = shipDet_conf.configure(run, ship_geo) primGen = r.FairPrimaryGenerator() primGen.SetTarget(ship_geo.target.z0 + 50 * u.m, 0.) MuonBackgen = r.MuonBackGenerator() MuonBackgen.Init(self.input_file, first_event, phiRandom) MuonBackgen.SetSmearBeam(3 * u.cm) # beam size mimicking spiral if self.same_seed: MuonBackgen.SetSameSeed(self.same_seed) primGen.AddGenerator(MuonBackgen) if not n_events: n_events = MuonBackgen.GetNevents() else: n_events = min(n_events, MuonBackgen.GetNevents()) print ('Process ', n_events, ' from input file, with Phi random=', phiRandom) if followMuon: modules['Veto'].SetFastMuon() run.SetGenerator(primGen) run.SetStoreTraj(r.kFALSE) run.Init() print ('Initialised run.') # geomGeant4.setMagnetField() if hasattr(ship_geo.Bfield, "fieldMap"): fieldMaker = geomGeant4.addVMCFields(ship_geo, '', True) print ('Start run of {} events.'.format(n_events)) run.Run(n_events) print ('Finished simulation of {} events.'.format(n_events)) geofile_output_path = os.path.join(self.output_dir, "geofile_full.fe_{}_n_events_{}.root" .format(first_event, n_events)) run.CreateGeometryFile(geofile_output_path) # save ShipGeo dictionary in geofile saveBasicParameters.execute(geofile_output_path, ship_geo) return run
def create_csv_field_map(options): r.gErrorIgnoreLevel = r.kWarning r.gSystem.Load('libpythia8') ship_geo = ConfigRegistry.loadpy( '$FAIRSHIP/geometry/geometry_config.py', Yheight=globalDesigns["dy"], tankDesign=globalDesigns["dv"], nuTauTargetDesign=globalDesigns["nud"], CaloDesign=globalDesigns["caloDesign"], strawDesign=globalDesigns["strawDesign"], muShieldDesign=options.ds, muShieldStepGeo=options.muShieldStepGeo, muShieldWithCobaltMagnet=options.muShieldWithCobaltMagnet, muShieldGeo=options.geofile) ship_geo.muShield.WithConstField = True run = r.FairRunSim() run.SetName('TGeant4') # Transport engine run.SetOutputFile("tmp_file") # Output file # user configuration file default g4Config.C run.SetUserConfig('g4Config.C') modules = shipDet_conf.configure(run, ship_geo) primGen = r.FairPrimaryGenerator() primGen.SetTarget(ship_geo.target.z0 + 70.845 * u.m, 0.) # run.SetGenerator(primGen) run.SetStoreTraj(r.kFALSE) run.Init() fieldMaker = geomGeant4.addVMCFields(ship_geo, '', True) field_center, shield_half_length = ShieldUtils.find_shield_center(ship_geo) print("SHIELD ONLY: CENTER: {}, HALFLENGTH: {}, half_X: {}, half_Y: {}". format(field_center, shield_half_length, ship_geo.muShield.half_X_max, ship_geo.muShield.half_Y_max)) fieldMaker.generateFieldMap( os.path.expandvars("$FAIRSHIP/files/fieldMap.csv"), 2.5, ship_geo.muShield.half_X_max, ship_geo.muShield.half_Y_max, shield_half_length, field_center)
run = ROOT.FairRunSim() run.SetName("TGeant4") # Transport engine run.SetOutputFile("dummy") # Output file run.SetUserConfig("g4Config_basic.C" ) # geant4 transport not used, only needed for the mag field rtdb = run.GetRuntimeDb() # -----Create geometry---------------------------------------------- print('a') modules = shipDet_conf.configure(run, ShipGeo) print('b') run.Init() print('c') import geomGeant4 print('d') if hasattr(ShipGeo.Bfield, "fieldMap"): fieldMaker = geomGeant4.addVMCFields(ShipGeo, '', True) print('e') sGeo = ROOT.gGeoManager print('f') geoMat = ROOT.genfit.TGeoMaterialInterface() print('g') ROOT.genfit.MaterialEffects.getInstance().init(geoMat) print('h') bfield = ROOT.genfit.FairShipFields() print('i') fM = ROOT.genfit.FieldManager.getInstance() print('j') fM.init(bfield) print('k') volDict = {} i = 0
ut.bookHist(h,'chi2','Chi2/DOF',100,0.,20.) import shipDet_conf run = ROOT.FairRunSim() run.SetName("TGeant4") # Transport engine run.SetOutputFile(ROOT.TMemFile('output', 'recreate')) # Output file run.SetUserConfig("g4Config_basic.C") # geant4 transport not used, only needed for creating VMC field rtdb = run.GetRuntimeDb() # -----Create geometry---------------------------------------------- modules = shipDet_conf.configure(run,ShipGeo) # run.Init() fgeo.FAIRGeom import geomGeant4 if hasattr(ShipGeo.Bfield,"fieldMap"): fieldMaker = geomGeant4.addVMCFields(ShipGeo, '', True,withVirtualMC = False) # make global variables builtin.debug = debug builtin.fieldMaker = fieldMaker builtin.pidProton = pidProton builtin.withT0 = withT0 builtin.realPR = realPR builtin.vertexing = vertexing builtin.ecalGeoFile = ecalGeoFile builtin.ShipGeo = ShipGeo builtin.modules = modules builtin.EcalDebugDraw = EcalDebugDraw builtin.withNoStrawSmearing = withNoStrawSmearing builtin.h = h builtin.log = log
20 * u.m, 20 * u.m, 200. * u.m) trajFilter.SetMomentumCutP(0.1 * u.GeV) trajFilter.SetEnergyCut(0., 400. * u.GeV) trajFilter.SetStorePrimaries(ROOT.kTRUE) trajFilter.SetStoreSecondaries(ROOT.kTRUE) # The VMC sets the fields using the "/mcDet/setIsLocalMagField true" option in "gconfig/g4config.in" import geomGeant4 # geomGeant4.setMagnetField() # replaced by VMC, only has effect if /mcDet/setIsLocalMagField false # Define extra VMC B fields not already set by the geometry definitions, e.g. a global field, # any field maps, or defining if any volumes feel only the local or local+global field. # For now, just keep the fields already defined by the C++ code, i.e comment out the fieldMaker if charm == 0: # charm and muflux testbeam not yet updated for using the new bfield interface if hasattr(ship_geo.Bfield, "fieldMap"): fieldMaker = geomGeant4.addVMCFields(ship_geo, '', True) # Print VMC fields and associated geometry objects if debug > 0: geomGeant4.printVMCFields() geomGeant4.printWeightsandFields(onlyWithField = True,\ exclude=['DecayVolume','Tr1','Tr2','Tr3','Tr4','Veto','Ecal','Hcal','MuonDetector','SplitCal']) # Plot the field example #fieldMaker.plotField(1, ROOT.TVector3(-9000.0, 6000.0, 50.0), ROOT.TVector3(-300.0, 300.0, 6.0), 'Bzx.png') #fieldMaker.plotField(2, ROOT.TVector3(-9000.0, 6000.0, 50.0), ROOT.TVector3(-400.0, 400.0, 6.0), 'Bzy.png') if inactivateMuonProcesses: ROOT.gROOT.ProcessLine('#include "Geant4/G4ProcessTable.hh"') mygMC = ROOT.TGeant4.GetMC() mygMC.ProcessGeantCommand("/process/inactivate muPairProd") mygMC.ProcessGeantCommand("/process/inactivate muBrems")
trajFilter.SetVertexCut(-20 * u.m, -20 * u.m, ship_geo.target.z0 - 1 * u.m, 20 * u.m, 20 * u.m, 200. * u.m) trajFilter.SetMomentumCutP(0.1 * u.GeV) trajFilter.SetEnergyCut(0., 400. * u.GeV) trajFilter.SetStorePrimaries(ROOT.kTRUE) trajFilter.SetStoreSecondaries(ROOT.kTRUE) # The VMC sets the fields using the "/mcDet/setIsLocalMagField true" option in "gconfig/g4config.in" import geomGeant4 # geomGeant4.setMagnetField() # replaced by VMC, only has effect if /mcDet/setIsLocalMagField false # Define extra VMC B fields not already set by the geometry definitions, e.g. a global field, # any field maps, or defining if any volumes feel only the local or local+global field. # For now, just keep the fields already defined by the C++ code, i.e comment out the fieldMaker if hasattr(ship_geo.Bfield, "fieldMap"): fieldMaker = geomGeant4.addVMCFields(ship_geo.Bfield.fieldMap, ship_geo.Bfield.z, True) # Print VMC fields and associated geometry objects if debug > 0: geomGeant4.printVMCFields() geomGeant4.printWeightsandFields(onlyWithField = True,\ exclude=['DecayVolume','Tr1','Tr2','Tr3','Tr4','Veto','Ecal','Hcal','MuonDetector','SplitCal']) # Plot the field example #fieldMaker.plotField(1, ROOT.TVector3(-9000.0, 6000.0, 50.0), ROOT.TVector3(-300.0, 300.0, 6.0), 'Bzx.png') #fieldMaker.plotField(2, ROOT.TVector3(-9000.0, 6000.0, 50.0), ROOT.TVector3(-400.0, 400.0, 6.0), 'Bzy.png') if inactivateMuonProcesses: ROOT.gROOT.ProcessLine('#include "Geant4/G4ProcessTable.hh"') mygMC = ROOT.TGeant4.GetMC() mygMC.ProcessGeantCommand("/process/inactivate muPairProd") mygMC.ProcessGeantCommand("/process/inactivate muBrems")
ecalGeoFile = ShipGeo.ecal.File dy = ShipGeo.Yheight/u.m # -----Create geometry---------------------------------------------- import shipDet_conf run = ROOT.FairRunSim() run.SetName("TGeant4") # Transport engine run.SetOutputFile(ROOT.TMemFile('output', 'recreate')) # Output file run.SetUserConfig("g4Config_basic.C") # geant4 transport not used, only needed for the mag field rtdb = run.GetRuntimeDb() # -----Create geometry---------------------------------------------- modules = shipDet_conf.configure(run,ShipGeo) run.Init() import geomGeant4 if hasattr(ShipGeo.Bfield,"fieldMap"): fieldMaker = geomGeant4.addVMCFields(ShipGeo, '', True) sGeo = ROOT.gGeoManager geoMat = ROOT.genfit.TGeoMaterialInterface() ROOT.genfit.MaterialEffects.getInstance().init(geoMat) bfield = ROOT.genfit.FairShipFields() fM = ROOT.genfit.FieldManager.getInstance() fM.init(bfield) volDict = {} i=0 for x in ROOT.gGeoManager.GetListOfVolumes(): volDict[i]=x.GetName() i+=1
def run_track_pattern_recognition(input_file, geo_file, output_file, method): """ Runs all steps of track pattern recognition. Parameters ---------- input_file : string Path to an input .root file with events. geo_file : string Path to a file with SHiP geometry. output_file : string Path to an output .root file with quality plots. method : string Name of a track pattern recognition method. """ ############################################# Load SHiP geometry ################################################### # Check geo file try: fgeo = ROOT.TFile(geo_file) except: print("An error with opening the ship geo file.") raise sGeo = fgeo.FAIRGeom # Prepare ShipGeo dictionary if not fgeo.FindKey('ShipGeo'): if sGeo.GetVolume('EcalModule3'): ecalGeoFile = "ecal_ellipse6x12m2.geo" else: ecalGeoFile = "ecal_ellipse5x10m2.geo" if dy: ShipGeo = ConfigRegistry.loadpy( "$FAIRSHIP/geometry/geometry_config.py", Yheight=dy, EcalGeoFile=ecalGeoFile) else: ShipGeo = ConfigRegistry.loadpy( "$FAIRSHIP/geometry/geometry_config.py", EcalGeoFile=ecalGeoFile) else: upkl = Unpickler(fgeo) ShipGeo = upkl.load('ShipGeo') # Globals builtin.ShipGeo = ShipGeo ############################################# Load SHiP modules #################################################### import shipDet_conf run = ROOT.FairRunSim() run.SetName("TGeant4") # Transport engine run.SetOutputFile("dummy") # Output file run.SetUserConfig( "g4Config_basic.C" ) # geant4 transport not used, only needed for the mag field rtdb = run.GetRuntimeDb() modules = shipDet_conf.configure(run, ShipGeo) run.Init() #run = ROOT.FairRunSim() #modules = shipDet_conf.configure(run,ShipGeo) ######################################### Load SHiP magnetic field ################################################# import geomGeant4 if hasattr(ShipGeo.Bfield, "fieldMap"): fieldMaker = geomGeant4.addVMCFields(ShipGeo, '', True, withVirtualMC=False) else: print("no fieldmap given, geofile too old, not anymore support") exit(-1) sGeo = fgeo.FAIRGeom geoMat = ROOT.genfit.TGeoMaterialInterface() ROOT.genfit.MaterialEffects.getInstance().init(geoMat) bfield = ROOT.genfit.FairShipFields() bfield.setField(fieldMaker.getGlobalField()) fM = ROOT.genfit.FieldManager.getInstance() fM.init(bfield) ############################################# Load inpur data file ################################################# # Check input file try: fn = ROOT.TFile(input_file, 'update') except: print("An error with opening the input data file.") raise sTree = fn.cbmsim sTree.Write() ############################################# Create hists ######################################################### h = init_book_hist() ########################################## Start Track Pattern Recognition ######################################### import shipPatRec # Init book of hists for the quality measurements metrics = { 'n_hits': [], 'reconstructible': 0, 'passed_y12': 0, 'passed_stereo12': 0, 'passed_12': 0, 'passed_y34': 0, 'passed_stereo34': 0, 'passed_34': 0, 'passed_combined': 0, 'reco_passed': 0, 'reco_passed_no_clones': 0, 'frac_y12': [], 'frac_stereo12': [], 'frac_12': [], 'frac_y34': [], 'frac_stereo34': [], 'frac_34': [], 'reco_frac_tot': [], 'reco_mc_p': [], 'reco_mc_theta': [], 'fitted_p': [], 'fitted_pval': [], 'fitted_chi': [], 'fitted_x': [], 'fitted_y': [], 'fitted_z': [], 'fitted_mass': [] } # Start event loop nEvents = sTree.GetEntries() for iEvent in range(nEvents): if iEvent % 1000 == 0: print('Event ', iEvent) ########################################### Select one event ################################################### rc = sTree.GetEvent(iEvent) ########################################### Reconstructible tracks ############################################# reconstructible_tracks = getReconstructibleTracks( iEvent, sTree, sGeo, ShipGeo) metrics['reconstructible'] += len(reconstructible_tracks) for i_reco in reconstructible_tracks: h['TracksPassed'].Fill("Reconstructible tracks", 1) h['TracksPassedU'].Fill("Reconstructible tracks", 1) in_y12 = [] in_stereo12 = [] in_12 = [] in_y34 = [] in_stereo34 = [] in_34 = [] in_combo = [] found_track_ids = [] n_tracks = len(reconstructible_tracks) n_recognized = 0 n_clones = 0 n_ghosts = 0 n_others = 0 min_eff = 0. ########################################## Recognized tracks ################################################### nTracklets = sTree.Tracklets.GetEntriesFast() for i_track in range(nTracklets): atracklet = sTree.Tracklets[i_track] if atracklet.getType() != 1: # this is a not full track (tracklet) continue atrack = atracklet.getList() if atrack.size() == 0: continue hits = { 'X': [], 'Y': [], 'Z': [], 'DetID': [], 'TrackID': [], 'Pz': [], 'Px': [], 'Py': [], 'dist2Wire': [], 'Pdg': [] } for ihit in atrack: ahit = sTree.strawtubesPoint[ihit] hits['X'] += [ahit.GetX()] hits['Y'] += [ahit.GetY()] hits['Z'] += [ahit.GetZ()] hits['DetID'] += [ahit.GetDetectorID()] hits['TrackID'] += [ahit.GetTrackID()] hits['Pz'] += [ahit.GetPz()] hits['Px'] += [ahit.GetPx()] hits['Py'] += [ahit.GetPy()] hits['dist2Wire'] += [ahit.dist2Wire()] hits['Pdg'] += [ahit.PdgCode()] # List to numpy arrays for key in hits.keys(): hits[key] = numpy.array(hits[key]) # Decoding statnb, vnb, pnb, lnb, snb = decodeDetectorID(hits['DetID']) is_stereo = ((vnb == 1) + (vnb == 2)) is_y = ((vnb == 0) + (vnb == 3)) is_before = ((statnb == 1) + (statnb == 2)) is_after = ((statnb == 3) + (statnb == 4)) # Metrics metrics['n_hits'] += [get_n_hits(hits['TrackID'])] # Tracks passed frac_y12, tmax_y12 = fracMCsame(hits['TrackID'][is_before * is_y]) n_hits_y12 = get_n_hits(hits['TrackID'][is_before * is_y]) frac_stereo12, tmax_stereo12 = fracMCsame( hits['TrackID'][is_before * is_stereo]) n_hits_stereo12 = get_n_hits(hits['TrackID'][is_before * is_stereo]) frac_12, tmax_12 = fracMCsame(hits['TrackID'][is_before]) n_hits_12 = get_n_hits(hits['TrackID'][is_before]) frac_y34, tmax_y34 = fracMCsame(hits['TrackID'][is_after * is_y]) n_hits_y34 = get_n_hits(hits['TrackID'][is_after * is_y]) frac_stereo34, tmax_stereo34 = fracMCsame( hits['TrackID'][is_after * is_stereo]) n_hits_stereo34 = get_n_hits(hits['TrackID'][is_after * is_stereo]) frac_34, tmax_34 = fracMCsame(hits['TrackID'][is_after]) n_hits_34 = get_n_hits(hits['TrackID'][is_after]) frac_tot, tmax_tot = fracMCsame(hits['TrackID']) n_hits_tot = get_n_hits(hits['TrackID']) if tmax_y12 == tmax_stereo12 and tmax_y12 == tmax_y34 and tmax_y12 == tmax_stereo34: if frac_y12 >= min_eff and frac_stereo12 >= min_eff and frac_y34 >= min_eff and frac_stereo34 >= min_eff: if tmax_y12 in reconstructible_tracks and tmax_y12 not in found_track_ids: n_recognized += 1 found_track_ids.append(tmax_y12) elif tmax_y12 in reconstructible_tracks and tmax_y12 in found_track_ids: n_clones += 1 elif tmax_y12 not in reconstructible_tracks: n_others += 1 else: n_ghosts += 1 else: n_ghosts += 1 is_reconstructed = 0 is_reconstructed_no_clones = 0 if tmax_y12 in reconstructible_tracks: metrics['passed_y12'] += 1 metrics['frac_y12'] += [frac_y12] h['TracksPassed'].Fill("Y view station 1&2", 1) if tmax_y12 not in in_y12: h['TracksPassedU'].Fill("Y view station 1&2", 1) in_y12.append(tmax_y12) if tmax_stereo12 == tmax_y12: metrics['passed_stereo12'] += 1 metrics['frac_stereo12'] += [frac_stereo12] h['TracksPassed'].Fill("Stereo station 1&2", 1) if tmax_stereo12 not in in_stereo12: h['TracksPassedU'].Fill("Stereo station 1&2", 1) in_stereo12.append(tmax_stereo12) if tmax_12 == tmax_y12: metrics['passed_12'] += 1 metrics['frac_12'] += [frac_12] h['TracksPassed'].Fill("station 1&2", 1) if tmax_12 not in in_12: h['TracksPassedU'].Fill("station 1&2", 1) in_12.append(tmax_12) if tmax_y34 in reconstructible_tracks: metrics['passed_y34'] += 1 metrics['frac_y34'] += [frac_y34] h['TracksPassed'].Fill("Y view station 3&4", 1) if tmax_y34 not in in_y34: h['TracksPassedU'].Fill( "Y view station 3&4", 1) in_y34.append(tmax_y34) if tmax_stereo34 == tmax_y34: metrics['passed_stereo34'] += 1 metrics['frac_stereo34'] += [frac_stereo34] h['TracksPassed'].Fill("Stereo station 3&4", 1) if tmax_stereo34 not in in_stereo34: h['TracksPassedU'].Fill( "Stereo station 3&4", 1) in_stereo34.append(tmax_stereo34) if tmax_34 == tmax_y34: metrics['passed_34'] += 1 metrics['frac_34'] += [frac_34] h['TracksPassed'].Fill("station 3&4", 1) if tmax_34 not in in_34: h['TracksPassedU'].Fill( "station 3&4", 1) in_34.append(tmax_34) if tmax_12 == tmax_34: metrics['passed_combined'] += 1 h['TracksPassed'].Fill( "Combined stations 1&2/3&4", 1) metrics['reco_passed'] += 1 is_reconstructed = 1 if tmax_34 not in in_combo: h['TracksPassedU'].Fill( "Combined stations 1&2/3&4", 1) metrics[ 'reco_passed_no_clones'] += 1 in_combo.append(tmax_34) is_reconstructed_no_clones = 1 # For reconstructed tracks if is_reconstructed == 0: continue metrics['reco_frac_tot'] += [frac_tot] # Momentum Pz = hits['Pz'] Px = hits['Px'] Py = hits['Py'] p, px, py, pz = getPtruthFirst(sTree, tmax_tot) pt = math.sqrt(px**2 + py**2) Z_true = [] X_true = [] Y_true = [] for ahit in sTree.strawtubesPoint: if ahit.GetTrackID() == tmax_tot: az, ax, ay = ahit.GetZ(), ahit.GetX(), ahit.GetY() Z_true.append(az) X_true.append(ax) Y_true.append(ay) metrics['reco_mc_p'] += [p] h['TracksPassed_p'].Fill(p, 1) # Direction Z = hits['Z'][(hits['TrackID'] == tmax_tot) * is_before] X = hits['X'][(hits['TrackID'] == tmax_tot) * is_before] Y = hits['Y'][(hits['TrackID'] == tmax_tot) * is_before] Z = Z - Z[0] X = X - X[0] Y = Y - Y[0] R = numpy.sqrt(X**2 + Y**2 + Z**2) Theta = numpy.arccos(Z[1:] / R[1:]) theta = numpy.mean(Theta) metrics['reco_mc_theta'] += [theta] h['n_hits_reco_y12'].Fill(n_hits_y12) h['n_hits_reco_stereo12'].Fill(n_hits_stereo12) h['n_hits_reco_12'].Fill(n_hits_12) h['n_hits_reco_y34'].Fill(n_hits_y34) h['n_hits_reco_stereo34'].Fill(n_hits_stereo34) h['n_hits_reco_34'].Fill(n_hits_34) h['n_hits_reco'].Fill(n_hits_tot) h['n_hits_y12'].Fill(p, n_hits_y12) h['n_hits_stereo12'].Fill(p, n_hits_stereo12) h['n_hits_12'].Fill(p, n_hits_12) h['n_hits_y34'].Fill(p, n_hits_y34) h['n_hits_stereo34'].Fill(p, n_hits_stereo34) h['n_hits_34'].Fill(p, n_hits_34) h['n_hits_total'].Fill(p, n_hits_tot) h['frac_y12'].Fill(p, frac_y12) h['frac_stereo12'].Fill(p, frac_stereo12) h['frac_12'].Fill(p, frac_12) h['frac_y34'].Fill(p, frac_y34) h['frac_stereo34'].Fill(p, frac_stereo34) h['frac_34'].Fill(p, frac_34) h['frac_total'].Fill(p, frac_tot) h['frac_y12_dist'].Fill(frac_y12) h['frac_stereo12_dist'].Fill(frac_stereo12) h['frac_12_dist'].Fill(frac_12) h['frac_y34_dist'].Fill(frac_y34) h['frac_stereo34_dist'].Fill(frac_stereo34) h['frac_34_dist'].Fill(frac_34) h['frac_total_dist'].Fill(frac_tot) # Fitted track thetrack = sTree.FitTracks[i_track] fitStatus = thetrack.getFitStatus() thetrack.prune( "CFL" ) # http://sourceforge.net/p/genfit/code/HEAD/tree/trunk/core/include/Track.h#l280 nmeas = fitStatus.getNdf() pval = fitStatus.getPVal() chi2 = fitStatus.getChi2() / nmeas metrics['fitted_pval'] += [pval] metrics['fitted_chi'] += [chi2] h['chi2fittedtracks'].Fill(chi2) h['pvalfittedtracks'].Fill(pval) try: fittedState = thetrack.getFittedState() fittedMom = fittedState.getMomMag() fittedMom = fittedMom #*int(charge) px_fit, py_fit, pz_fit = fittedState.getMom().x( ), fittedState.getMom().y(), fittedState.getMom().z() p_fit = fittedMom pt_fit = math.sqrt(px_fit**2 + py_fit**2) metrics['fitted_p'] += [p_fit] perr = (p - p_fit) / p h['ptrue-p/ptrue'].Fill(perr) h['perr'].Fill(p, perr) h['perr_direction'].Fill(numpy.rad2deg(theta), perr) pterr = (pt - pt_fit) / pt h['pttrue-pt/pttrue'].Fill(pterr) pxerr = (px - px_fit) / px h['pxtrue-px/pxtrue'].Fill(pxerr) pyerr = (py - py_fit) / py h['pytrue-py/pytrue'].Fill(pyerr) pzerr = (pz - pz_fit) / pz h['pztrue-pz/pztrue'].Fill(pzerr) if math.fabs(p) > 0.0: h['pvspfitted'].Fill(p, fittedMom) fittedtrackDir = fittedState.getDir() fittedx = math.degrees(math.acos(fittedtrackDir[0])) fittedy = math.degrees(math.acos(fittedtrackDir[1])) fittedz = math.degrees(math.acos(fittedtrackDir[2])) fittedmass = fittedState.getMass() h['momentumfittedtracks'].Fill(fittedMom) h['xdirectionfittedtracks'].Fill(fittedx) h['ydirectionfittedtracks'].Fill(fittedy) h['zdirectionfittedtracks'].Fill(fittedz) h['massfittedtracks'].Fill(fittedmass) metrics['fitted_x'] += [fittedx] metrics['fitted_y'] += [fittedy] metrics['fitted_z'] += [fittedz] metrics['fitted_mass'] += [fittedmass] Z_fit = [] X_fit = [] Y_fit = [] for az in Z_true: rc, pos, mom = extrapolateToPlane(thetrack, az) Z_fit.append(pos.Z()) X_fit.append(pos.X()) Y_fit.append(pos.Y()) for i in range(len(Z_true)): xerr = abs(X_fit[i] - X_true[i]) yerr = abs(Y_fit[i] - Y_true[i]) h['abs(x - x-true)'].Fill(xerr) h['abs(y - y-true)'].Fill(yerr) rmse_x = numpy.sqrt( numpy.mean((numpy.array(X_fit) - numpy.array(X_true))**2)) rmse_y = numpy.sqrt( numpy.mean((numpy.array(Y_fit) - numpy.array(Y_true))**2)) h['rmse_x'].Fill(rmse_x) h['rmse_y'].Fill(rmse_y) except: print("Problem with fitted state.") h['Reco_tracks'].Fill("N total", n_tracks) h['Reco_tracks'].Fill("N recognized tracks", n_recognized) h['Reco_tracks'].Fill("N clones", n_clones) h['Reco_tracks'].Fill("N ghosts", n_ghosts) h['Reco_tracks'].Fill("N others", n_others) ############################################# Save hists ######################################################### save_hists(h, output_file) return metrics
trajFilter.SetVertexCut(-20*u.m, -20*u.m,ship_geo.target.z0-1*u.m, 20*u.m, 20*u.m, 200.*u.m) trajFilter.SetMomentumCutP(0.1*u.GeV) trajFilter.SetEnergyCut(0., 400.*u.GeV) trajFilter.SetStorePrimaries(ROOT.kTRUE) trajFilter.SetStoreSecondaries(ROOT.kTRUE) # The VMC sets the fields using the "/mcDet/setIsLocalMagField true" option in "gconfig/g4config.in" import geomGeant4 # geomGeant4.setMagnetField() # replaced by VMC, only has effect if /mcDet/setIsLocalMagField false # Define extra VMC B fields not already set by the geometry definitions, e.g. a global field, # any field maps, or defining if any volumes feel only the local or local+global field. # For now, just keep the fields already defined by the C++ code, i.e comment out the fieldMaker if charm == 0: # charm and muflux testbeam not yet updated for using the new bfield interface if hasattr(ship_geo.Bfield,"fieldMap"): fieldMaker = geomGeant4.addVMCFields(ship_geo, '', True) # Print VMC fields and associated geometry objects if debug > 0: geomGeant4.printVMCFields() geomGeant4.printWeightsandFields(onlyWithField = True,\ exclude=['DecayVolume','Tr1','Tr2','Tr3','Tr4','Veto','Ecal','Hcal','MuonDetector','SplitCal']) # Plot the field example #fieldMaker.plotField(1, ROOT.TVector3(-9000.0, 6000.0, 50.0), ROOT.TVector3(-300.0, 300.0, 6.0), 'Bzx.png') #fieldMaker.plotField(2, ROOT.TVector3(-9000.0, 6000.0, 50.0), ROOT.TVector3(-400.0, 400.0, 6.0), 'Bzy.png') if inactivateMuonProcesses : ROOT.gROOT.ProcessLine('#include "Geant4/G4ProcessTable.hh"') mygMC = ROOT.TGeant4.GetMC() mygMC.ProcessGeantCommand("/process/inactivate muPairProd") mygMC.ProcessGeantCommand("/process/inactivate muBrems")
gFairBaseContFact = ROOT.FairBaseContFact( ) # required by change to FairBaseContFact to avoid TList::Clear errors run = ROOT.FairRunSim() run.SetName("TGeant4") # Transport engine run.SetOutputFile("dummy") # Output file run.SetUserConfig( "g4Config_basic.C" ) # geant4 transport not used, only needed for creating VMC field rtdb = run.GetRuntimeDb() # -----Create geometry---------------------------------------------- modules = shipDet_conf.configure(run, ShipGeo) run.Init() import geomGeant4 if hasattr(ShipGeo.Bfield, "fieldMap"): fieldMaker = geomGeant4.addVMCFields(ShipGeo.Bfield.fieldMap, ShipGeo.Bfield.z, True) # make global variables builtin.debug = debug builtin.pidProton = pidProton builtin.withT0 = withT0 builtin.realPR = realPR builtin.vertexing = vertexing builtin.ecalGeoFile = ecalGeoFile builtin.ShipGeo = ShipGeo builtin.modules = modules builtin.EcalDebugDraw = EcalDebugDraw builtin.withNoStrawSmearing = withNoStrawSmearing builtin.h = h builtin.log = log iEvent = 0
def run_track_pattern_recognition(input_file, geo_file, output_file, method): """ Runs all steps of track pattern recognition. Parameters ---------- input_file : string Path to an input .root file with events. geo_file : string Path to a file with SHiP geometry. output_file : string Path to an output .root file with quality plots. method : string Name of a track pattern recognition method. """ ############################################# Load SHiP geometry ################################################### # Check geo file try: fgeo = ROOT.TFile(geo_file) except: print "An error with opening the ship geo file." raise sGeo = fgeo.FAIRGeom # Prepare ShipGeo dictionary if not fgeo.FindKey('ShipGeo'): if sGeo.GetVolume('EcalModule3') : ecalGeoFile = "ecal_ellipse6x12m2.geo" else: ecalGeoFile = "ecal_ellipse5x10m2.geo" if dy: ShipGeo = ConfigRegistry.loadpy("$FAIRSHIP/geometry/geometry_config.py", Yheight = dy, EcalGeoFile = ecalGeoFile) else: ShipGeo = ConfigRegistry.loadpy("$FAIRSHIP/geometry/geometry_config.py", EcalGeoFile = ecalGeoFile) else: upkl = Unpickler(fgeo) ShipGeo = upkl.load('ShipGeo') # Globals builtin.ShipGeo = ShipGeo ############################################# Load SHiP modules #################################################### import shipDet_conf run = ROOT.FairRunSim() run.SetName("TGeant4") # Transport engine run.SetOutputFile("dummy") # Output file run.SetUserConfig("g4Config_basic.C") # geant4 transport not used, only needed for the mag field rtdb = run.GetRuntimeDb() modules = shipDet_conf.configure(run,ShipGeo) run.Init() #run = ROOT.FairRunSim() #modules = shipDet_conf.configure(run,ShipGeo) ######################################### Load SHiP magnetic field ################################################# import geomGeant4 if hasattr(ShipGeo.Bfield,"fieldMap"): fieldMaker = geomGeant4.addVMCFields(ShipGeo, '', True, withVirtualMC = False) else: print "no fieldmap given, geofile too old, not anymore support" exit(-1) sGeo = fgeo.FAIRGeom geoMat = ROOT.genfit.TGeoMaterialInterface() ROOT.genfit.MaterialEffects.getInstance().init(geoMat) bfield = ROOT.genfit.FairShipFields() bfield.setField(fieldMaker.getGlobalField()) fM = ROOT.genfit.FieldManager.getInstance() fM.init(bfield) ############################################# Load inpur data file ################################################# # Check input file try: fn = ROOT.TFile(input_file,'update') except: print "An error with opening the input data file." raise sTree = fn.cbmsim sTree.Write() ############################################# Create hists ######################################################### h = init_book_hist() ########################################## Start Track Pattern Recognition ######################################### import shipPatRec # Init book of hists for the quality measurements metrics = {'n_hits': [], 'reconstructible': 0, 'passed_y12': 0, 'passed_stereo12': 0, 'passed_12': 0, 'passed_y34': 0, 'passed_stereo34': 0, 'passed_34': 0, 'passed_combined': 0, 'reco_passed': 0, 'reco_passed_no_clones': 0, 'frac_y12': [], 'frac_stereo12': [], 'frac_12': [], 'frac_y34': [], 'frac_stereo34': [], 'frac_34': [], 'reco_frac_tot': [], 'reco_mc_p': [], 'reco_mc_theta': [], 'fitted_p': [], 'fitted_pval': [], 'fitted_chi': [], 'fitted_x': [], 'fitted_y': [], 'fitted_z': [], 'fitted_mass': []} # Start event loop nEvents = sTree.GetEntries() for iEvent in range(nEvents): if iEvent%1000 == 0: print 'Event ', iEvent ########################################### Select one event ################################################### rc = sTree.GetEvent(iEvent) ########################################### Reconstructible tracks ############################################# reconstructible_tracks = getReconstructibleTracks(iEvent, sTree, sGeo, ShipGeo) metrics['reconstructible'] += len(reconstructible_tracks) for i_reco in reconstructible_tracks: h['TracksPassed'].Fill("Reconstructible tracks", 1) h['TracksPassedU'].Fill("Reconstructible tracks", 1) in_y12 = [] in_stereo12 = [] in_12 = [] in_y34 = [] in_stereo34 = [] in_34 = [] in_combo = [] found_track_ids = [] n_tracks = len(reconstructible_tracks) n_recognized = 0 n_clones = 0 n_ghosts = 0 n_others = 0 min_eff = 0. ########################################## Recognized tracks ################################################### nTracklets = sTree.Tracklets.GetEntriesFast() for i_track in range(nTracklets): atracklet = sTree.Tracklets[i_track] if atracklet.getType() != 1: # this is a not full track (tracklet) continue atrack = atracklet.getList() if atrack.size() == 0: continue hits = {'X': [], 'Y': [], 'Z': [], 'DetID': [], 'TrackID': [], 'Pz': [], 'Px': [], 'Py': [], 'dist2Wire': [], 'Pdg': []} for ihit in atrack: ahit = sTree.strawtubesPoint[ihit] hits['X'] += [ahit.GetX()] hits['Y'] += [ahit.GetY()] hits['Z'] += [ahit.GetZ()] hits['DetID'] += [ahit.GetDetectorID()] hits['TrackID'] += [ahit.GetTrackID()] hits['Pz'] += [ahit.GetPz()] hits['Px'] += [ahit.GetPx()] hits['Py'] += [ahit.GetPy()] hits['dist2Wire'] += [ahit.dist2Wire()] hits['Pdg'] += [ahit.PdgCode()] # List to numpy arrays for key in hits.keys(): hits[key] = numpy.array(hits[key]) # Decoding statnb, vnb, pnb, lnb, snb = decodeDetectorID(hits['DetID']) is_stereo = ((vnb == 1) + (vnb == 2)) is_y = ((vnb == 0) + (vnb == 3)) is_before = ((statnb == 1) + (statnb == 2)) is_after = ((statnb == 3) + (statnb == 4)) # Metrics metrics['n_hits'] += [get_n_hits(hits['TrackID'])] # Tracks passed frac_y12, tmax_y12 = fracMCsame(hits['TrackID'][is_before * is_y]) n_hits_y12 = get_n_hits(hits['TrackID'][is_before * is_y]) frac_stereo12, tmax_stereo12 = fracMCsame(hits['TrackID'][is_before * is_stereo]) n_hits_stereo12 = get_n_hits(hits['TrackID'][is_before * is_stereo]) frac_12, tmax_12 = fracMCsame(hits['TrackID'][is_before]) n_hits_12 = get_n_hits(hits['TrackID'][is_before]) frac_y34, tmax_y34 = fracMCsame(hits['TrackID'][is_after * is_y]) n_hits_y34 = get_n_hits(hits['TrackID'][is_after * is_y]) frac_stereo34, tmax_stereo34 = fracMCsame(hits['TrackID'][is_after * is_stereo]) n_hits_stereo34 = get_n_hits(hits['TrackID'][is_after * is_stereo]) frac_34, tmax_34 = fracMCsame(hits['TrackID'][is_after]) n_hits_34 = get_n_hits(hits['TrackID'][is_after]) frac_tot, tmax_tot = fracMCsame(hits['TrackID']) n_hits_tot = get_n_hits(hits['TrackID']) if tmax_y12 == tmax_stereo12 and tmax_y12 == tmax_y34 and tmax_y12 == tmax_stereo34: if frac_y12 >= min_eff and frac_stereo12 >= min_eff and frac_y34 >= min_eff and frac_stereo34 >= min_eff: if tmax_y12 in reconstructible_tracks and tmax_y12 not in found_track_ids: n_recognized += 1 found_track_ids.append(tmax_y12) elif tmax_y12 in reconstructible_tracks and tmax_y12 in found_track_ids: n_clones += 1 elif tmax_y12 not in reconstructible_tracks: n_others += 1 else: n_ghosts += 1 else: n_ghosts += 1 is_reconstructed = 0 is_reconstructed_no_clones = 0 if tmax_y12 in reconstructible_tracks: metrics['passed_y12'] += 1 metrics['frac_y12'] += [frac_y12] h['TracksPassed'].Fill("Y view station 1&2", 1) if tmax_y12 not in in_y12: h['TracksPassedU'].Fill("Y view station 1&2", 1) in_y12.append(tmax_y12) if tmax_stereo12 == tmax_y12: metrics['passed_stereo12'] += 1 metrics['frac_stereo12'] += [frac_stereo12] h['TracksPassed'].Fill("Stereo station 1&2", 1) if tmax_stereo12 not in in_stereo12: h['TracksPassedU'].Fill("Stereo station 1&2", 1) in_stereo12.append(tmax_stereo12) if tmax_12 == tmax_y12: metrics['passed_12'] += 1 metrics['frac_12'] += [frac_12] h['TracksPassed'].Fill("station 1&2", 1) if tmax_12 not in in_12: h['TracksPassedU'].Fill("station 1&2", 1) in_12.append(tmax_12) if tmax_y34 in reconstructible_tracks: metrics['passed_y34'] += 1 metrics['frac_y34'] += [frac_y34] h['TracksPassed'].Fill("Y view station 3&4", 1) if tmax_y34 not in in_y34: h['TracksPassedU'].Fill("Y view station 3&4", 1) in_y34.append(tmax_y34) if tmax_stereo34 == tmax_y34: metrics['passed_stereo34'] += 1 metrics['frac_stereo34'] += [frac_stereo34] h['TracksPassed'].Fill("Stereo station 3&4", 1) if tmax_stereo34 not in in_stereo34: h['TracksPassedU'].Fill("Stereo station 3&4", 1) in_stereo34.append(tmax_stereo34) if tmax_34 == tmax_y34: metrics['passed_34'] += 1 metrics['frac_34'] += [frac_34] h['TracksPassed'].Fill("station 3&4", 1) if tmax_34 not in in_34: h['TracksPassedU'].Fill("station 3&4", 1) in_34.append(tmax_34) if tmax_12 == tmax_34: metrics['passed_combined'] += 1 h['TracksPassed'].Fill("Combined stations 1&2/3&4", 1) metrics['reco_passed'] += 1 is_reconstructed = 1 if tmax_34 not in in_combo: h['TracksPassedU'].Fill("Combined stations 1&2/3&4", 1) metrics['reco_passed_no_clones'] += 1 in_combo.append(tmax_34) is_reconstructed_no_clones = 1 # For reconstructed tracks if is_reconstructed == 0: continue metrics['reco_frac_tot'] += [frac_tot] # Momentum Pz = hits['Pz'] Px = hits['Px'] Py = hits['Py'] p, px, py, pz = getPtruthFirst(sTree, tmax_tot) pt = math.sqrt(px**2 + py**2) Z_true = [] X_true = [] Y_true = [] for ahit in sTree.strawtubesPoint: if ahit.GetTrackID() == tmax_tot: az, ax, ay = ahit.GetZ(),ahit.GetX(),ahit.GetY() Z_true.append(az) X_true.append(ax) Y_true.append(ay) metrics['reco_mc_p'] += [p] h['TracksPassed_p'].Fill(p, 1) # Direction Z = hits['Z'][(hits['TrackID'] == tmax_tot) * is_before] X = hits['X'][(hits['TrackID'] == tmax_tot) * is_before] Y = hits['Y'][(hits['TrackID'] == tmax_tot) * is_before] Z = Z - Z[0] X = X - X[0] Y = Y - Y[0] R = numpy.sqrt(X**2 + Y**2 + Z**2) Theta = numpy.arccos(Z[1:] / R[1:]) theta = numpy.mean(Theta) metrics['reco_mc_theta'] += [theta] h['n_hits_reco_y12'].Fill(n_hits_y12) h['n_hits_reco_stereo12'].Fill(n_hits_stereo12) h['n_hits_reco_12'].Fill(n_hits_12) h['n_hits_reco_y34'].Fill(n_hits_y34) h['n_hits_reco_stereo34'].Fill(n_hits_stereo34) h['n_hits_reco_34'].Fill(n_hits_34) h['n_hits_reco'].Fill(n_hits_tot) h['n_hits_y12'].Fill(p, n_hits_y12) h['n_hits_stereo12'].Fill(p, n_hits_stereo12) h['n_hits_12'].Fill(p, n_hits_12) h['n_hits_y34'].Fill(p, n_hits_y34) h['n_hits_stereo34'].Fill(p, n_hits_stereo34) h['n_hits_34'].Fill(p, n_hits_34) h['n_hits_total'].Fill(p, n_hits_tot) h['frac_y12'].Fill(p, frac_y12) h['frac_stereo12'].Fill(p, frac_stereo12) h['frac_12'].Fill(p, frac_12) h['frac_y34'].Fill(p, frac_y34) h['frac_stereo34'].Fill(p, frac_stereo34) h['frac_34'].Fill(p, frac_34) h['frac_total'].Fill(p, frac_tot) h['frac_y12_dist'].Fill(frac_y12) h['frac_stereo12_dist'].Fill(frac_stereo12) h['frac_12_dist'].Fill(frac_12) h['frac_y34_dist'].Fill(frac_y34) h['frac_stereo34_dist'].Fill(frac_stereo34) h['frac_34_dist'].Fill(frac_34) h['frac_total_dist'].Fill(frac_tot) # Fitted track thetrack = sTree.FitTracks[i_track] fitStatus = thetrack.getFitStatus() thetrack.prune("CFL") # http://sourceforge.net/p/genfit/code/HEAD/tree/trunk/core/include/Track.h#l280 nmeas = fitStatus.getNdf() pval = fitStatus.getPVal() chi2 = fitStatus.getChi2() / nmeas metrics['fitted_pval'] += [pval] metrics['fitted_chi'] += [chi2] h['chi2fittedtracks'].Fill(chi2) h['pvalfittedtracks'].Fill(pval) try: fittedState = thetrack.getFittedState() fittedMom = fittedState.getMomMag() fittedMom = fittedMom #*int(charge) px_fit,py_fit,pz_fit = fittedState.getMom().x(),fittedState.getMom().y(),fittedState.getMom().z() p_fit = fittedMom pt_fit = math.sqrt(px_fit**2 + py_fit**2) metrics['fitted_p'] += [p_fit] perr = (p - p_fit) / p h['ptrue-p/ptrue'].Fill(perr) h['perr'].Fill(p, perr) h['perr_direction'].Fill(numpy.rad2deg(theta), perr) pterr = (pt - pt_fit) / pt h['pttrue-pt/pttrue'].Fill(pterr) pxerr = (px - px_fit) / px h['pxtrue-px/pxtrue'].Fill(pxerr) pyerr = (py - py_fit) / py h['pytrue-py/pytrue'].Fill(pyerr) pzerr = (pz - pz_fit) / pz h['pztrue-pz/pztrue'].Fill(pzerr) if math.fabs(p) > 0.0 : h['pvspfitted'].Fill(p, fittedMom) fittedtrackDir = fittedState.getDir() fittedx=math.degrees(math.acos(fittedtrackDir[0])) fittedy=math.degrees(math.acos(fittedtrackDir[1])) fittedz=math.degrees(math.acos(fittedtrackDir[2])) fittedmass = fittedState.getMass() h['momentumfittedtracks'].Fill(fittedMom) h['xdirectionfittedtracks'].Fill(fittedx) h['ydirectionfittedtracks'].Fill(fittedy) h['zdirectionfittedtracks'].Fill(fittedz) h['massfittedtracks'].Fill(fittedmass) metrics['fitted_x'] += [fittedx] metrics['fitted_y'] += [fittedy] metrics['fitted_z'] += [fittedz] metrics['fitted_mass'] += [fittedmass] Z_fit = [] X_fit = [] Y_fit = [] for az in Z_true: rc,pos,mom = extrapolateToPlane(thetrack, az) Z_fit.append(pos.Z()) X_fit.append(pos.X()) Y_fit.append(pos.Y()) for i in range(len(Z_true)): xerr = abs(X_fit[i] - X_true[i]) yerr = abs(Y_fit[i] - Y_true[i]) h['abs(x - x-true)'].Fill(xerr) h['abs(y - y-true)'].Fill(yerr) rmse_x = numpy.sqrt(numpy.mean((numpy.array(X_fit) - numpy.array(X_true))**2)) rmse_y = numpy.sqrt(numpy.mean((numpy.array(Y_fit) - numpy.array(Y_true))**2)) h['rmse_x'].Fill(rmse_x) h['rmse_y'].Fill(rmse_y) except: print "Problem with fitted state." h['Reco_tracks'].Fill("N total", n_tracks) h['Reco_tracks'].Fill("N recognized tracks", n_recognized) h['Reco_tracks'].Fill("N clones", n_clones) h['Reco_tracks'].Fill("N ghosts", n_ghosts) h['Reco_tracks'].Fill("N others", n_others) ############################################# Save hists ######################################################### save_hists(h, output_file) return metrics