def stdSigmas(listtype='std', gammatype='pi0eff50', path=None): """ Load standard ``Sigma+`` reconstructed from ``Sigma+ -> p+ [pi0 -> gamma gamma]```. The ``pi0`` is reconstructed using the specified gamma list and ``pi0``s in mass range ``100 ~ 160 MeV`` are combined the with protons from ``p+:loose`` list to form a ``Sigma+``. Tree fitter is used for the vertex fit with IP constraint and mass constraint on the ``pi0``. The particle list is named ``Sigma+:std`` with mass range ``1.66 ~ 1.22 GeV``. Parameters: gamma_type (str): the gamma list to use path (basf2.path): path to load the particle list """ stdPhotons(gammatype, path=path) stdPr('loose', path=path) ma.reconstructDecay( f'pi0:for_sigma -> gamma:{gammatype} gamma:{gammatype}', '0.1 < M < 0.16', path=path) ma.reconstructDecay('Sigma+:std -> p+:loose pi0:for_sigma', '1.1 < M < 1.3', path=path) ma.vertexTree('Sigma+:std', 0, ipConstraint=True, massConstraint=[111], updateAllDaughters=False, path=path) ma.applyCuts('Sigma+:std', '1.16 < M < 1.22', path=path) if listtype == 'std': pass elif listtype == 'loose': vtx_cuts = 'cosaXY > 0.99 and dr > 0.12 and abs(dz) > 0.1 and chiProb > 0.001' ma.cutAndCopyList('Sigma+:loose', 'Sigma+:std', vtx_cuts, path=path) else: B2ERROR( f'stdSigmas: Invalid listtype ({listtype}. Choose from std, loose.' )
ntuple_vars = sigma_vars + proton_vars + pi0_vars + gamma_vars + event_vars # Reconstruction # ============================================== # Standard PID cuts for charged final state particles ma.fillParticleList('p+:good', 'pid_ppi >= 0.6 and pid_pk >= 0.6', path=mp) ma.reconstructDecay('Sigma+:loose -> p+:good pi0:mdst', 'M >= 1.0 and M <= 1.4', path=mp) ## !!! Have to set updateAllDaughters = True because the pi0:mdst list is mass constrained ma.vertexTree('Sigma+:loose', 0, ipConstraint=True, updateAllDaughters=True, path=mp) ma.applyCuts('Sigma+:loose', 'M >= 1.1 and M <= 1.3', path=mp) # ma.matchMCTruth('Sigma+:loose', path = mp) # mp.add_module('VariablesToNtuple', particleList = 'Sigma+:loose', # variables=ntuple_vars, treeName='sigma_loose', fileName=sys.argv[2]) # Eff of this cut is about 96% and rejects about 50% of the background for Sigma+ pi0_mass_cut = 'daughter(1, M) >= 0.12 and daughter(1, M) <= 0.15' ma.cutAndCopyList('Sigma+:good', 'Sigma+:loose', pi0_mass_cut, path=mp) ma.vertexTree('Sigma+:good', 0, ipConstraint=True, massConstraint=[], updateAllDaughters=False, path=mp) ma.applyCuts('Sigma+:good', 'M >= 1.16 and M <= 1.22', path=mp) ma.matchMCTruth('Sigma+:good', path=mp)
ma.cutAndCopyList('p+:berger', 'p+:all', 'pid_ppi > 0.6 and pid_pk > 0.6', path=mp) # M Berger: photons > 40 MeV and pi0 lab frame momentum > 100 MeV ma.cutAndCopyList( 'pi0:berger', 'pi0:mdst', 'daughter(0, E) > 0.05 and daughter(0, E) > 0.05 and p > 0.1', path=mp) ma.reconstructDecay('Sigma+:berger_loose -> p+:berger pi0:berger', 'M >= 1.0 and M <= 1.4', path=mp) # Set updateAllDaughters = True because the pi0:mdst list is mass constrained ma.vertexTree('Sigma+:berger_loose', 0, ipConstraint=True, massConstraint=[111], path=mp) # M Berger: discard condidates with wrong sign of flight distance ma.applyCuts('Sigma+:berger_loose', 'M >= 1.15 and M <= 1.225', path=mp) ma.matchMCTruth('Sigma+:berger_loose', path=mp) mp.add_module('VariablesToNtuple', particleList='Sigma+:berger_loose', variables=ntuple_vars, treeName='sigma_loose', fileName=sys.argv[2]) b2.process(path=mp) print(b2.statistics)
gamma_vars = create_aliases_for_selected(['phi', 'theta', 'E', 'goodBelleGamma', 'clusterReg', 'clusterE9E21', 'clusterTiming', 'clusterErrorTiming', 'genMotherPDG', 'isSignal'], 'Sigma+ -> p+ [pi0 -> ^gamma ^gamma]', prefix = ['gamma1', 'gamma2']) ntuple_vars = sigma_vars + proton_vars + pi0_vars + gamma_vars + event_vars # RECONSTRUCTION # ============================================== ma.fillParticleList('p+:all', '', path = mp) # M Berger: standard pairwise PID > 0.6 and impact parameter > 0.003 ma.cutAndCopyList('p+:berger', 'p+:all', 'pid_ppi > 0.6 and pid_pk > 0.6', path = mp) # M Berger: photons > 40 MeV and pi0 lab frame momentum > 100 MeV ma.cutAndCopyList('pi0:loose', 'pi0:mdst', '', path = mp) ma.reconstructDecay('Sigma+:loose -> p+:berger pi0:loose', 'M >= 1.15 and M <= 1.23', path = mp) # Set updateAllDaughters = True because the pi0:mdst list is mass constrained ma.vertexTree('Sigma+:loose', 0, ipConstraint = True, updateAllDaughters=True, path = mp) # M Berger: discard condidates with wrong sign of flight distance ma.cutAndCopyList('Sigma+:good', 'Sigma+:loose', 'gamma1_E > 0.03 and gamma2_E > 0.03 and pi0_M >= 0.11 and pi0_M <= 0.16 and pi0_p > 0.05', path = mp) ma.vertexTree('Sigma+:good', 0, ipConstraint = True, massConstraint = [111], path = mp) ma.applyCuts('Sigma+:good', 'M >= 1.17 and M <= 1.21', path = mp) ma.matchMCTruth('Sigma+:good', path = mp) mp.add_module('VariablesToNtuple', particleList = 'Sigma+:good', variables=ntuple_vars, treeName='good', fileName=sys.argv[2]) b2.process(path=mp) print(b2.statistics)
# Training labels 'eventExtraInfo(smartBKG)', ] if __name__ == '__main__': args = GetCmdArgs() os.makedirs(os.path.dirname(args.out_file), exist_ok=True) # Load the input skim file path = ma.create_path() ma.inputMdstList('MC9', filelist=[], path=path) # ma.inputMdstList('default', filelist=[], path=path) ma.applyCuts(particle_list, 'nCleanedTracks(dr<2 and abs(dz)<4) <= 12', path=path) print(event_vars) # Apply the smartBKG NN model # Will use extraInfo saved as training labels later, # need to be flattened before training to 0 or 1 NNApplyModule_m = NNApplyModule( model_file=args.model, model_type='combined-wideCNN', threshold=0., # threshold=args.threshold, extra_info_var='smartBKG' ) # dead_path = b2.create_path()
# combine J/psi and KS candidates to form B0 candidates ma.reconstructDecay('B0 -> J/psi:ee K_S0:merged', cut='Mbc > 5.2 and abs(deltaE) < 0.3', path=main) # match reconstructed with MC particles ma.matchMCTruth('B0', path=main) # build the rest of the event ma.buildRestOfEvent('B0', fillWithMostLikely=True, path=main) # call flavor tagging ft.flavorTagger('B0', path=main) # remove B0 candidates without a valid flavor information ma.applyCuts('B0', 'qrOutput(FBDT) > -2', path=main) # fit B vertex on the tag-side vertex.TagV('B0', constraintType='tube', fitAlgorithm='Rave', path=main) # perform best candidate selection #b2.set_random_seed('USBelleIISummerSchool') #ma.rankByHighest('B0', variable='random', numBest=1, path=main) # create list of variables for output ntuple standard_vars = vc.kinematics + vc.mc_kinematics + vc.mc_truth fs_vars = vc.pid + vc.track + vc.track_hits + standard_vars jpsi_ks_vars = vc.inv_mass + vc.vertex + vc.mc_vertex + standard_vars b_vars = vc.deltae_mbc + vc.tag_vertex + vc.mc_tag_vertex + ft.flavor_tagging + standard_vars b_vars += vu.create_aliases_for_selected([*fs_vars, 'isBremsCorrected'],
va.addAlias('p_decayAngle', 'decayAngle(0)') va.addAlias('pi0_decayAngle', 'decayAngle(1)') ma.fillParticleList('p+:good', 'pid_ppi > 0.6 and pid_pk > 0.6', path=mp) # ma.vertexTree('pi0:mdst', ipConstraint = True, massConstraint = ['pi0'], path = mp) ma.reconstructDecay('Sigma+:std -> p+:good pi0:mdst', '1.1 < M < 1.3', path=mp) ma.vertexTree('Sigma+:std', 0, ipConstraint=True, updateAllDaughters=True, path=mp) # Select good pi0 based on mass and gamma energy ma.applyCuts( 'Sigma+:std', 'daughter(1, daughter(0, E)) > 0.04 and daughter(1, daughter(1, E)) > 0.04 and daughter(1, abs(dM)) < 0.02', path=mp) ma.vertexTree('Sigma+:std', 0, ipConstraint=True, massConstraint=['pi0'], path=mp) # 100 MeV mass window for Sigma+ should be large enough ma.applyCuts('Sigma+:std', 'cosaXY > 0 and daughter(1, p) > 0.1 and 1.16 < M < 1.22', path=mp) ma.matchMCTruth('Sigma+:std', path=mp) ntuple = [ 'M', 'p', 'chiProb', 'cosa', 'cosaXY', 'dr', 'dz', 'distance', 'isSignal', 'genMotherPDG'
# Load the input skim file path = ma.create_path() ma.inputMdstList('MC9', filelist=[], path=path) # Build some event specific ROE and continuum vars ma.buildRestOfEvent(particle_list, path=path) ROEMask = ('ROE', IPtrack_cut, gamma_cut) ma.appendROEMasks(particle_list, [ROEMask], path=path) ma.buildContinuumSuppression(particle_list, roe_mask='ROE', path=path) B_vars += ROE_vars print(B_vars) # Then choose one candidate per event # Dont' need to, want to view changes to candidates overall # But let's try for fun ma.rankByHighest(particle_list, 'extraInfo(SignalProbability)', outputVariable='FEIProbabilityRank', path=path) ma.applyCuts(particle_list, 'extraInfo(FEIProbabilityRank) == 1', path=path) # Write output ma.variablesToNtuple( particle_list, B_vars, filename=args.out_file, path=path, ) b2.process(path) print(b2.statistics)
variables.addAlias('pi0Likeness','extraInfo(Pi0_Prob)') variables.addAlias('etaLikeness','extraInfo(Eta_Prob)') variables.addAlias('cosThetaCMS','useCMSFrame(cosTheta)') variables.addAlias('pCMS','useCMSFrame(p)') variables.addAlias('ECMS','useCMSFrame(E)') variables.addAlias('m12','daughterInvariantMass(0,1)') variables.addAlias('m13','daughterInvariantMass(0,2)') variables.addAlias('m23','daughterInvariantMass(1,2)') main_path = b2.create_path() # Declaration of main path bp.add_beamparameters(main_path,'Y4S') ma.inputMdst('MC10', inputFilename, path=main_path) sv.goodBelleKshort(path=main_path) sg.stdPhotons('loose', path=main_path) sc.stdPi('95eff', path=main_path) ma.applyCuts('gamma:loose','1.4 < E < 4', path=main_path) krescuts = " and daughterInvM(0,1,2) < 2 and daughterInvM(0,1) > 0.6 and daughterInvM(0,1) < 0.9" #reconstructDecay(Kres+":all -> pi+:good pi-:good K_S0:all", krescuts) ma.reconstructDecay("B0:signal -> pi+:95eff pi-:95eff K_S0:legacyGoodKS gamma:loose", "Mbc > 5.2 and deltaE < 0.2 and deltaE > -0.2 and -0.65 < daughter(1, cosTheta) < 0.85"+krescuts, path=main_path) ma.vertexRave('B0:signal',0.0001, 'B0 -> ^pi+ ^pi- ^K_S0 gamma', path=main_path) #vertexTree('B0:signal',0.0001) ma.rankByHighest('B0:signal',ratingVar, 1, outputVariable='myRating', path=main_path) ma.buildRestOfEvent('B0:signal', path=main_path) # define the "cleaner" mask eclCut = '[E > 0.062 and abs(clusterTiming) < 18 and clusterReg==1] or \ [E>0.060 and abs(clusterTiming) < 20 and clusterReg==2] or \
list_pid = ['pid_ppi', 'pid_pk', 'pid_kpi'] list_event = ['IPX', 'IPY', 'IPZ'] # Variables # ============================================= # Lambda0 list_ntuple = list_basics + list_lambda + list_event + list_mc # proton and pion list_ntuple += create_aliases_for_selected(list_basics + list_pid + list_mc, 'Lambda0 -> ^p+ ^pi-', prefix=['p', 'pi']) # Reconstruction # ============================================== # No reconstruction. Just MC match the Lambda0:mdst list ma.vertexTree('Lambda0:mdst', 0, path=mp) ma.matchMCTruth('Lambda0:mdst', path=mp) ma.applyCuts('Lambda0:mdst', 'isSignal == 0', path=mp) # Output # ============================================= mp.add_module('VariablesToNtuple', particleList='Lambda0:mdst', variables=list_ntuple, treeName='lambda', fileName=sys.argv[2]) b2.process(path=mp) print(b2.statistics)
ma.reconstructDecay(f'pi0:for_sigma -> gamma:for_pi0 gamma:for_pi0', '0.1 < M < 0.16', path=mp) stdPr('loose', path=mp) # good tracks and protonID > 0.1 ma.reconstructDecay('Sigma+:loose -> p+:loose pi0:for_sigma', '1.1 < M < 1.3', path=mp) # Have to use ipConstraint otherwise not enough degrees of freedom ma.vertexTree('Sigma+:loose', 0, ipConstraint=True, massConstraint=[111], updateAllDaughters=False, path=mp) ma.applyCuts('Sigma+:loose', 'abs(dM) < 0.03', path=mp) ma.matchMCTruth('Sigma+:loose', path=mp) va.addAlias('cosa', 'cosAngleBetweenMomentumAndVertexVector') va.addAlias('cosaXY', 'cosAngleBetweenMomentumAndVertexVectorInXYPlane') va.addAlias('abs_dM', 'abs(dM)') va.addAlias('M_noupdate', 'extraInfo(M_noupdate)') va.addAlias('p_noupdate', 'extraInfo(p_noupdate)') ntuple = [ 'M', 'p', 'chiProb', 'cosa', 'cosaXY', 'dr', 'dz', 'distance', 'isSignal', 'genMotherPDG' ] ntuple += ['IPX', 'IPY', 'IPZ'] ntuple += create_aliases_for_selected(
ipConstraint=True, updateAllDaughters=True, path=mp) # M Berger: discard condidates with wrong sign of flight distance ma.cutAndCopyList( 'Sigma+:good', 'Sigma+:loose', 'gamma1_E > 0.03 and gamma2_E > 0.03 and pi0_M >= 0.11 and pi0_M <= 0.16 and pi0_p > 0.05', path=mp) ma.vertexTree('Sigma+:good', 0, ipConstraint=True, massConstraint=[111], path=mp) ma.applyCuts('Sigma+:good', 'M >= 1.17 and M <= 1.21', path=mp) # ma.matchMCTruth('Sigma+:good', path = mp) mp.add_module('MVAExpert', listNames=['Sigma+:good'], extraInfoName='Sigma_mva', identifier='MVA_Sigma_p.root') variables.addAlias('Sigma_mva', 'extraInfo(Sigma_mva)') ma.applyCuts('Sigma+:good', 'extraInfo(Sigma_mva) > 0.2', path=mp) lamc_pi_vars = create_aliases_for_selected( [ 'p', 'M', 'dr', 'dz', 'pid_ppi', 'pid_kpi', 'pid_pk', 'mcPDG', 'genMotherPDG', 'isSignal' ],
# with 3 different samples of at least 500k events (one for each sampler). # Three different 500k events samples are needed in order to avoid biases between levels. # We mean 500k of correctly corrected and MC matched neutral Bs. (isSignal > 0) # You can also train track and event level for all categories (1st to 4th runs) and then train the combiner # for a specific combination (last two runs). # It is also possible to train different combiners consecutively using the same weightFiles name. # You just need always to specify the desired category combination while using the expert mode as: # # flavorTagger(particleLists=['B0:jspipi0'], mode = 'Expert', weightFiles='B2JpsiKs_mu', # categories=['Electron', 'Muon', 'Kaon', ... etc.]) # # Another possibility is to train a combiner for a specific category combination using the default weight files # You can apply cuts using the flavor Tagger: qrOutput(FBDT) > -2 rejects all events which do not # provide flavor information using the tag side ma.applyCuts(list_name='B0:jspipi0', cut='qrOutput(FBDT) > -2', path=my_path) # If you applied the cut on qrOutput(FBDT) > -2 before then you can rank by highest r- factor ma.rankByHighest(particleList='B0:jspipi0', variable='abs(qrOutput(FBDT))', numBest=0, outputVariable='Dilution_rank', path=my_path) # Fit Vertex of the B0 on the tag side vx.TagV(list_name='B0:jspipi0', MCassociation='breco', confidenceLevel=0.001, useFitAlgorithm='standard_PXD', path=my_path)