From d29633866ecf93992fc3943823b1f767824cb82c Mon Sep 17 00:00:00 2001 From: mvoorde <48947870+mvoorde@users.noreply.github.com> Date: Fri, 31 Mar 2023 13:33:03 +0200 Subject: [PATCH] Add reconstructed analysis files --- .../ExoticHiggsDecays/Reco_analysis_final.py | 119 +++++++++ .../ExoticHiggsDecays/Reco_analysis_plots.py | 88 +++++++ .../ExoticHiggsDecays/Reco_analysis_stage1.py | 236 ++++++++++++++++++ 3 files changed, 443 insertions(+) create mode 100644 examples/FCCee/bsm/LLPs/ExoticHiggsDecays/Reco_analysis_final.py create mode 100644 examples/FCCee/bsm/LLPs/ExoticHiggsDecays/Reco_analysis_plots.py create mode 100644 examples/FCCee/bsm/LLPs/ExoticHiggsDecays/Reco_analysis_stage1.py diff --git a/examples/FCCee/bsm/LLPs/ExoticHiggsDecays/Reco_analysis_final.py b/examples/FCCee/bsm/LLPs/ExoticHiggsDecays/Reco_analysis_final.py new file mode 100644 index 0000000000..8de0aabb64 --- /dev/null +++ b/examples/FCCee/bsm/LLPs/ExoticHiggsDecays/Reco_analysis_final.py @@ -0,0 +1,119 @@ +#Input directory where the files produced at the stage1 level are +inputDir = "/eos/experiment/fcc/ee/analyses/case-studies/bsm/LLPs/H_SS_4b/Reco_output_stage1/" + +#Output directory where the files produced at the final-selection level are +outputDir = "Reco_output_finalSel/" + + +# # #Integrated luminosity for scaling number of events (required only if setting doScale to true) +# intLumi = 5e6 #pb^-1 + +# # #Scale event yields by intLumi and cross section (optional) +# doScale = True + +# # #Save event yields in a table (optional) +# saveTabular = True + +#Mandatory: List of processes +processList = { + + #privately-produced signals + 'exoticHiggs_scalar_ms20GeV_sine-5':{}, + 'exoticHiggs_scalar_ms20GeV_sine-6':{}, + 'exoticHiggs_scalar_ms20GeV_sine-7':{}, + 'exoticHiggs_scalar_ms60GeV_sine-5':{}, + 'exoticHiggs_scalar_ms60GeV_sine-6':{}, + 'exoticHiggs_scalar_ms60GeV_sine-7':{}, + + #centrally produced backgrounds + 'p8_ee_ZZ_ecm240':{}, + 'p8_ee_WW_ecm240':{}, + 'p8_ee_ZH_ecm240':{}, +} + +###Dictionary for prettier names of processes (optional) +processLabels = { + #signals + 'exoticHiggs_scalar_ms20GeV_sine-5': "$m_S$ = 20 GeV, sin $\theta = 1 * 10^{-5}$", + 'exoticHiggs_scalar_ms20GeV_sine-6': "$m_S$ = 20 GeV, sin $\theta = 1 * 10^{-6}$", + 'exoticHiggs_scalar_ms20GeV_sine-7': "$m_S$ = 20 GeV, sin $\theta = 1 * 10^{-7}$", + 'exoticHiggs_scalar_ms60GeV_sine-5': "$m_S$ = 60 GeV, sin $\theta = 1 * 10^{-5}$", + 'exoticHiggs_scalar_ms60GeV_sine-6': "$m_S$ = 60 GeV, sin $\theta = 1 * 10^{-6}$", + 'exoticHiggs_scalar_ms60GeV_sine-7': "$m_S$ = 60 GeV, sin $\theta = 1 * 10^{-7}$", + + #backgrounds + 'p8_ee_WW_ecm240': "e^{-}e^{+} $\rightarrow$ WW", + 'p8_ee_ZZ_ecm240': "e^{-}e^{+} $\rightarrow$ ZZ", + 'p8_ee_ZH_ecm240': "e^{-}e^{+} $\rightarrow$ ZH", +} + +#Link to the dictonary that contains all the cross section information etc... +procDict = "FCCee_procDict_spring2021_IDEA.json" + +#Add MySample_p8_ee_ZH_ecm240 as it is not an offical process +procDictAdd={ + 'exoticHiggs_scalar_ms20GeV_sine-5': {"numberOfEvents": 10000, "sumOfWeights": 10000, "crossSection": 8.858e-6, "kfactor": 1.0, "matchingEfficiency": 1.0}, + 'exoticHiggs_scalar_ms20GeV_sine-6': {"numberOfEvents": 10000, "sumOfWeights": 10000, "crossSection": 8.858e-6, "kfactor": 1.0, "matchingEfficiency": 1.0}, + 'exoticHiggs_scalar_ms20GeV_sine-7': {"numberOfEvents": 10000, "sumOfWeights": 10000, "crossSection": 8.858e-6, "kfactor": 1.0, "matchingEfficiency": 1.0}, + 'exoticHiggs_scalar_ms60GeV_sine-5': {"numberOfEvents": 10000, "sumOfWeights": 10000, "crossSection": 2.618e-6, "kfactor": 1.0, "matchingEfficiency": 1.0}, + 'exoticHiggs_scalar_ms60GeV_sine-6': {"numberOfEvents": 10000, "sumOfWeights": 10000, "crossSection": 2.618e-6, "kfactor": 1.0, "matchingEfficiency": 1.0}, + 'exoticHiggs_scalar_ms60GeV_sine-7': {"numberOfEvents": 10000, "sumOfWeights": 10000, "crossSection": 2.618e-6, "kfactor": 1.0, "matchingEfficiency": 1.0}, +} + +#Number of CPUs to use +nCPUS = 2 + +#produces ROOT TTrees, default is False +doTree = False + +###Dictionnay of the list of cuts. The key is the name of the selection that will be added to the output file +cutList = { + # For plotting + "selNone": "n_tracks > -1", + + # For event selection + "preSel": "((n_RecoElectrons>1) && (RecoElectron_charge.at(0) != RecoElectron_charge.at(1))) || ((n_RecoMuons>1) && (RecoMuon_charge.at(0) != RecoMuon_charge.at(1)))", + "selZ": "(Reco_ee_invMass > 70 && Reco_ee_invMass < 110) || (Reco_mumu_invMass > 70 && Reco_mumu_invMass < 110)", + "selZ+nDVs_seltracks": "((Reco_ee_invMass > 70 && Reco_ee_invMass < 110) || (Reco_mumu_invMass > 70 && Reco_mumu_invMass < 110)) && filter_n_DVs_seltracks > 1", + "selZ+nDVs_merge": "((Reco_ee_invMass > 70 && Reco_ee_invMass < 110) || (Reco_mumu_invMass > 70 && Reco_mumu_invMass < 110)) && filter_n_DVs_merge > 1", +} + +###Dictionary for prettier names of cuts (optional) +cutLabels = { + # For plotting + "selNone": "Before selection", + + # For event selection + "preSel": "At least 2 oppositely charged leptons", + "selZ": "70 < $m_{ll}$ < 110 GeV", + "selZ+nDVs_seltracks": "n DVs $\geq$ 2", + "selZ+nDVs_merge": "n DVs $\geq$ 2 (merged)", +} + +###Dictionary for the ouput variable/hitograms. The key is the name of the variable in the output files. "name" is the name of the variable in the input file, "title" is the x-axis label of the histogram, "bin" the number of bins of the histogram, "xmin" the minimum x-axis value and "xmax" the maximum x-axis value. + +histoList = { + "n_tracks": {"name":"n_tracks", "title":"Number of reconstructed tracks", "bin":100, "xmin":-0.5,"xmax":99.5}, + "n_RecoedPrimaryTracks": {"name":"n_RecoedPrimaryTracks", "title": "Number of reconstructed primary tracks", "bin":10, "xmin":-0.5,"xmax":9.5}, + 'n_seltracks_DVs': {"name":"n_seltracks_DVs", "title":"Number of DVs", "bin":12, "xmin":-0.5, "xmax":11.5}, + 'n_trks_seltracks_DVs': {"name":'n_trks_seltracks_DVs', "title":"Number of tracks from the DVs", "bin":30, "xmin":1.5, "xmax":29.5}, + 'invMass_seltracks_DVs': {"name":'invMass_seltracks_DVs', "title":"Invariant mass at the DVs [GeV]", "bin":40, "xmin":-0.5, "xmax":39.5}, + "DV_evt_seltracks_chi2": {"name":"DV_evt_seltracks_chi2", "title":"The #chi^{2} distribution of the DVs", "bin":100, "xmin":-0.5, "xmax":11.5}, + "Reco_seltracks_DVs_Lxy": {"name":"Reco_seltracks_DVs_Lxy", "title":"Transverse distance between PV and DVs [mm]", "bin":100, "xmin":0, "xmax":300}, + "Reco_seltracks_DVs_Lxyz": {"name":"Reco_seltracks_DVs_Lxyz", "title":"Distance between PV and DVs [mm]", "bin":100, "xmin":0, "xmax":2000}, + "DV_evt_seltracks_normchi2": {"name":"DV_evt_seltracks_normchi2", "title":"The normalised #chi^{2} distribution of the DVs", "bin":40, "xmin":0, "xmax":10}, + "merged_DVs_n": {"name":"merged_DVs_n", "title":"Number of DVs", "bin":10, "xmin":-0.5, "xmax":9.5}, + 'n_trks_merged_DVs': {"name":'n_trks_merged_DVs', "title":"Number of tracks from the DVs from sel tracks + merge", "bin":30, "xmin":1.5, "xmax":29.5}, + 'invMass_merged_DVs': {"name":'invMass_merged_DVs', "title":"Invariant mass at the DVs [GeV]", "bin":40, "xmin":-0.5, "xmax":39.5}, + "merged_DVs_chi2": {"name":"merged_DVs_chi2", "title":"The #chi^{2} distribution of the merged DVs", "bin":100, "xmin":-0.5, "xmax":11.5}, + "merged_DVs_normchi2": {"name":"merged_DVs_normchi2", "title":"The normalised #chi^{2} distribution of the merged DVs", "bin":40, "xmin":0, "xmax":10}, + "Reco_DVs_merged_Lxy": {"name":"Reco_DVs_merged_Lxy", "title":"Transverse distance between PV and DVs [mm]", "bin":100, "xmin":0, "xmax":300}, + "Reco_DVs_merged_Lxyz": {"name":"Reco_DVs_merged_Lxyz", "title":"Distance between PV and DVs [mm]", "bin":100, "xmin":0, "xmax":2000}, + + 'n_RecoElectrons': {"name":'n_RecoElectrons', "title": "Number of reconstructed electrons", "bin":10,"xmin":-0.5,"xmax":9.5}, + "Reco_ee_invMass": {"name":"Reco_ee_invMass", "title": "Invariant mass of reconstructed e- e+ [GeV]", "bin":100,"xmin":50,"xmax":150}, + 'n_RecoMuons': {"name":'n_RecoMuons', "title": "Number of reconstructed muons", "bin":10,"xmin":-0.5,"xmax":9.5}, + "Reco_mumu_invMass": {"name":"Reco_mumu_invMass", "title": "Invariant mass of reconstructed #mu- #mu+ [GeV]", "bin":100,"xmin":50,"xmax":150}, + + +} diff --git a/examples/FCCee/bsm/LLPs/ExoticHiggsDecays/Reco_analysis_plots.py b/examples/FCCee/bsm/LLPs/ExoticHiggsDecays/Reco_analysis_plots.py new file mode 100644 index 0000000000..e6f13ed4dc --- /dev/null +++ b/examples/FCCee/bsm/LLPs/ExoticHiggsDecays/Reco_analysis_plots.py @@ -0,0 +1,88 @@ +import ROOT + +# global parameters +intLumi = 5.0e+06 #in pb-1 + +###If scaleSig=0 or scaleBack=0, we don't apply any additional scaling, on top of the normalization to cross section and integrated luminosity, as defined in finalSel.py +###If scaleSig or scaleBack is not defined, plots will be normalized to 1 +#scaleSig = 0. +#scaleBack = 0. +ana_tex = 'e^{+}e^{-} #rightarrow Z h, Z #rightarrow l^{+}l^{-}, h #rightarrow ss #rightarrow b #bar{b} b #bar{b}' +delphesVersion = '3.4.2' +energy = 240 +collider = 'FCC-ee' +inputDir = 'Reco_output_finalSelPlots/' +#formats = ['png','pdf'] +formats = ['pdf'] +# yaxis = ['lin','log'] +yaxis = ['log'] +stacksig = ['nostack'] +outdir = 'Reco_plots/' +splitLeg = True + +variables = [ + + #gen variables + "n_tracks", + "n_RecoedPrimaryTracks", + 'n_seltracks_DVs', + 'n_trks_seltracks_DVs', + 'invMass_seltracks_DVs', + "DV_evt_seltracks_chi2", + "Reco_seltracks_DVs_Lxy", + "Reco_seltracks_DVs_Lxyz", + "DV_evt_seltracks_normchi2", + "merged_DVs_n", + 'n_trks_merged_DVs', + 'invMass_merged_DVs', + "merged_DVs_chi2", + "merged_DVs_normchi2", + "Reco_DVs_merged_Lxy", + "Reco_DVs_merged_Lxyz", + + 'n_RecoElectrons', + "Reco_ee_invMass", + 'n_RecoMuons', + "Reco_mumu_invMass", + ] + + +###Dictionary with the analysis name as a key, and the list of selections to be plotted for this analysis. The name of the selections should be the same than in the final selection +selections = {} +selections['ExoticHiggs'] = [ + "selNone", +] + +extralabel = {} +extralabel['selNone'] = "Before selection" + +colors = {} +colors['exoticHiggs_scalar_ms20GeV_sine-5'] = ROOT.kRed +colors['exoticHiggs_scalar_ms20GeV_sine-6'] = ROOT.kBlue +colors['exoticHiggs_scalar_ms20GeV_sine-7'] = ROOT.kGreen +colors['exoticHiggs_scalar_ms60GeV_sine-5'] = ROOT.kBlack +colors['exoticHiggs_scalar_ms60GeV_sine-6'] = ROOT.kOrange+1 +colors['exoticHiggs_scalar_ms60GeV_sine-7'] = ROOT.kViolet-4 + +plots = {} +plots['ExoticHiggs'] = {'signal':{ + 'exoticHiggs_scalar_ms20GeV_sine-5':['exoticHiggs_scalar_ms20GeV_sine-5'], + 'exoticHiggs_scalar_ms20GeV_sine-6':['exoticHiggs_scalar_ms20GeV_sine-6'], + 'exoticHiggs_scalar_ms20GeV_sine-7':['exoticHiggs_scalar_ms20GeV_sine-7'], + 'exoticHiggs_scalar_ms60GeV_sine-5':['exoticHiggs_scalar_ms60GeV_sine-5'], + 'exoticHiggs_scalar_ms60GeV_sine-6':['exoticHiggs_scalar_ms60GeV_sine-6'], + 'exoticHiggs_scalar_ms60GeV_sine-7':['exoticHiggs_scalar_ms60GeV_sine-7'], +}, +'backgrounds':{ + # + } + } + + +legend = {} +legend['exoticHiggs_scalar_ms20GeV_sine-5'] = 'm_{S} = 20 GeV, sin #theta = 1e-5' +legend['exoticHiggs_scalar_ms20GeV_sine-6'] = 'm_{S} = 20 GeV, sin #theta = 1e-6' +legend['exoticHiggs_scalar_ms20GeV_sine-7'] = 'm_{S} = 20 GeV, sin #theta = 1e-7' +legend['exoticHiggs_scalar_ms60GeV_sine-5'] = 'm_{S} = 60 GeV, sin #theta = 1e-5' +legend['exoticHiggs_scalar_ms60GeV_sine-6'] = 'm_{S} = 60 GeV, sin #theta = 1e-6' +legend['exoticHiggs_scalar_ms60GeV_sine-7'] = 'm_{S} = 60 GeV, sin #theta = 1e-7' diff --git a/examples/FCCee/bsm/LLPs/ExoticHiggsDecays/Reco_analysis_stage1.py b/examples/FCCee/bsm/LLPs/ExoticHiggsDecays/Reco_analysis_stage1.py new file mode 100644 index 0000000000..885e354016 --- /dev/null +++ b/examples/FCCee/bsm/LLPs/ExoticHiggsDecays/Reco_analysis_stage1.py @@ -0,0 +1,236 @@ +import ROOT + +#Mandatory: List of processes +processList = { + + #privately-produced signals + 'exoticHiggs_scalar_ms20GeV_sine-5':{}, + 'exoticHiggs_scalar_ms20GeV_sine-6':{}, + 'exoticHiggs_scalar_ms20GeV_sine-7':{}, + 'exoticHiggs_scalar_ms60GeV_sine-5':{}, + 'exoticHiggs_scalar_ms60GeV_sine-6':{}, + 'exoticHiggs_scalar_ms60GeV_sine-7':{}, + + # #centrally produced backgrounds + # 'p8_ee_ZH_ecm240':{'fraction':0.01}, + # 'p8_ee_ZZ_ecm240':{'fraction':0.01}, + # 'p8_ee_WW_ecm240':{'fraction':0.01}, +} + +#Production tag. This points to the yaml files for getting sample statistics +#Mandatory when running over EDM4Hep centrally produced events +#Comment out when running over privately produced events +#prodTag = "FCCee/spring2021/IDEA/" + + +#Input directory +#Comment out when running over centrally produced events +#Mandatory when running over privately produced events +inputDir = "/eos/experiment/fcc/ee/analyses/case-studies/bsm/LLPs/H_SS_4b/output_MadgraphPythiaDelphes/" + + +#Optional: output directory, default is local dir +#outputDir = "/eos/experiment/fcc/ee/analyses/case-studies/bsm/LLPs/H_SS_4b/Reco_output_stage1/" +#outputDirEos = "/eos/experiment/fcc/ee/analyses/case-studies/bsm/LLPs/H_SS_4b/Reco_output_stage1/" +outputDir = "Reco_output_stage1/" + +#Optional: ncpus, default is 4 +nCPUS = 8 + +#Optional running on HTCondor, default is False +runBatch = False +#runBatch = True + +#Optional batch queue name when running on HTCondor, default is workday +#batchQueue = "longlunch" + +#Optional computing account when running on HTCondor, default is group_u_FCC.local_gen +#compGroup = "group_u_FCC.local_gen" + +#USER DEFINED CODE +# For costum displaced vertex selection, apply selection on the DVs with invariant mass higher than 1 GeV and distance from PV to DV less than 2000 mm, but longer than 4 mm +# and count the number of DVs that fulfill this selection +ROOT.gInterpreter.Declare(""" +int filter_n_DVs(ROOT::VecOps::RVec distanceDV, ROOT::VecOps::RVec invMassDV) { + int result = 0; + for (size_t i = 0; i < invMassDV.size(); ++i) { + if (invMassDV.at(i) > 1 && distanceDV.at(i) > 4 && distanceDV.at(i) < 2000) + result += 1; + } + return result; +} +""") +#END USER DEFINED CODE + +#Mandatory: RDFanalysis class where the use defines the operations on the TTree +class RDFanalysis(): + + #__________________________________________________________ + #Mandatory: analysers funtion to define the analysers to process, please make sure you return the last dataframe, in this example it is df2 + def analysers(df): + df2 = ( + df + + .Alias("Particle1", "Particle#1.index") + .Alias("MCRecoAssociations0", "MCRecoAssociations#0.index") + .Alias("MCRecoAssociations1", "MCRecoAssociations#1.index") + + # MC event primary vertex + .Define("MC_PrimaryVertex", "FCCAnalyses::MCParticle::get_EventPrimaryVertex(21)( Particle )" ) + + # number of tracks + .Define("n_tracks","ReconstructedParticle2Track::getTK_n(EFlowTrack_1)") + + # Vertex fitting + + # First, reconstruct a vertex from all tracks + # Input parameters are 1 = primary vertex, EFlowTrack_1 contains all tracks, bool beamspotconstraint = true, bsc sigma x/y/z + .Define("VertexObject_allTracks", "VertexFitterSimple::VertexFitter_Tk ( 1, EFlowTrack_1, true, 4.5, 20e-3, 300)") + + # Select the tracks that are reconstructed as primaries + .Define("RecoedPrimaryTracks", "VertexFitterSimple::get_PrimaryTracks( VertexObject_allTracks, EFlowTrack_1, true, 4.5, 20e-3, 300, 0., 0., 0., 0)") + .Define("n_RecoedPrimaryTracks", "ReconstructedParticle2Track::getTK_n( RecoedPrimaryTracks )") + + # the final primary vertex : + .Define("PrimaryVertexObject", "VertexFitterSimple::VertexFitter_Tk ( 1, RecoedPrimaryTracks, true, 4.5, 20e-3, 300) ") + .Define("PrimaryVertex", "VertexingUtils::get_VertexData( PrimaryVertexObject )") + + # Displaced vertex reconstruction + + # select tracks with pT > 1 GeV + .Define('sel_tracks_pt', 'VertexingUtils::sel_pt_tracks(1)(EFlowTrack_1)') + # select tracks with |d0 |> 2 mm + .Define('sel_tracks', 'VertexingUtils::sel_d0_tracks(2)(sel_tracks_pt)') + # find the DVs + .Define("DV_evt_seltracks", "VertexFinderLCFIPlus::get_SV_event(sel_tracks, PrimaryVertexObject, true, 9., 40., 5.)") + # number of DVs + .Define('n_seltracks_DVs', 'VertexingUtils::get_n_SV(DV_evt_seltracks)') + # number of tracks from the DVs + .Define('n_trks_seltracks_DVs', 'VertexingUtils::get_VertexNtrk(DV_evt_seltracks)') + # invariant mass at the DVs (assuming the tracks to be pions) + .Define('invMass_seltracks_DVs', 'VertexingUtils::get_invM(DV_evt_seltracks)') + + # get the chi2 distributions of the DVs from selected tracks + .Define("DV_evt_seltracks_chi2", "VertexingUtils::get_chi2_SV(DV_evt_seltracks)") + .Define("DV_evt_seltracks_normchi2","VertexingUtils::get_norm_chi2_SV(DV_evt_seltracks)") # DV chi2 (normalised) + + # get the decay radius of all the DVs from selected tracks + .Define("Reco_seltracks_DVs_Lxy","VertexingUtils::get_dxy_SV(DV_evt_seltracks, PrimaryVertexObject)") + .Define("Reco_seltracks_DVs_Lxyz","VertexingUtils::get_d3d_SV(DV_evt_seltracks, PrimaryVertexObject)") + + # merge vertices with position within 10*error-of-position, get the tracks from the merged vertices and refit + .Define('merged_DVs', 'VertexingUtils::mergeVertices(DV_evt_seltracks)') + # number of merged DVs + .Define("merged_DVs_n", "VertexingUtils::get_n_SV(merged_DVs)") + # number of tracks from the merged DVs + .Define('n_trks_merged_DVs', 'VertexingUtils::get_VertexNtrk(merged_DVs)') + # invariant mass at the merged DVs + .Define('invMass_merged_DVs', 'VertexingUtils::get_invM(merged_DVs)') + + # get the chi2 distributions of the merged DVs + .Define("merged_DVs_chi2", "VertexingUtils::get_chi2_SV(merged_DVs)") + .Define("merged_DVs_normchi2","VertexingUtils::get_norm_chi2_SV(merged_DVs)") # DV chi2 (normalised) + + # get the decay radius of all the merged DVs + .Define("Reco_DVs_merged_Lxy","VertexingUtils::get_dxy_SV(merged_DVs, PrimaryVertexObject)") + .Define("Reco_DVs_merged_Lxyz","VertexingUtils::get_d3d_SV(merged_DVs, PrimaryVertexObject)") + + # Reconstructed electrons and muons + + # Electrons + .Alias('Electron0', 'Electron#0.index') + .Define('RecoElectrons', 'ReconstructedParticle::get(Electron0, ReconstructedParticles)') + .Define('n_RecoElectrons', 'ReconstructedParticle::get_n(RecoElectrons)') #count how many electrons are in the event in total + + # some kinematics of the reconstructed electrons and positrons + .Define("RecoElectron_e", "ReconstructedParticle::get_e(RecoElectrons)") + .Define("RecoElectron_p", "ReconstructedParticle::get_p(RecoElectrons)") + .Define("RecoElectron_pt", "ReconstructedParticle::get_pt(RecoElectrons)") + .Define("RecoElectron_px", "ReconstructedParticle::get_px(RecoElectrons)") + .Define("RecoElectron_py", "ReconstructedParticle::get_py(RecoElectrons)") + .Define("RecoElectron_pz", "ReconstructedParticle::get_pz(RecoElectrons)") + .Define("RecoElectron_charge", "ReconstructedParticle::get_charge(RecoElectrons)") + + # finding the invariant mass of the reconstructed electron and positron pair + .Define("Reco_ee_energy", "if ((n_RecoElectrons>1) && (RecoElectron_charge.at(0) != RecoElectron_charge.at(1))) return (RecoElectron_e.at(0) + RecoElectron_e.at(1)); else return float(-1.);") + .Define("Reco_ee_px", "if ((n_RecoElectrons>1) && (RecoElectron_charge.at(0) != RecoElectron_charge.at(1))) return (RecoElectron_px.at(0) + RecoElectron_px.at(1)); else return float(-1.);") + .Define("Reco_ee_py", "if ((n_RecoElectrons>1) && (RecoElectron_charge.at(0) != RecoElectron_charge.at(1))) return (RecoElectron_py.at(0) + RecoElectron_py.at(1)); else return float(-1.);") + .Define("Reco_ee_pz", "if ((n_RecoElectrons>1) && (RecoElectron_charge.at(0) != RecoElectron_charge.at(1))) return (RecoElectron_pz.at(0) + RecoElectron_pz.at(1)); else return float(-1.);") + .Define("Reco_ee_invMass", "if ((n_RecoElectrons>1) && (RecoElectron_charge.at(0) != RecoElectron_charge.at(1))) return sqrt(Reco_ee_energy*Reco_ee_energy - Reco_ee_px*Reco_ee_px - Reco_ee_py*Reco_ee_py - Reco_ee_pz*Reco_ee_pz ); else return float(-1.);") + + + # Muons + .Alias('Muon0', 'Muon#0.index') + .Define('RecoMuons', 'ReconstructedParticle::get(Muon0, ReconstructedParticles)') + .Define('n_RecoMuons', 'ReconstructedParticle::get_n(RecoMuons)') #count how many muons are in the event in total + + # some kinematics of the reconstructed muons + .Define("RecoMuon_e", "ReconstructedParticle::get_e(RecoMuons)") + .Define("RecoMuon_p", "ReconstructedParticle::get_p(RecoMuons)") + .Define("RecoMuon_pt", "ReconstructedParticle::get_pt(RecoMuons)") + .Define("RecoMuon_px", "ReconstructedParticle::get_px(RecoMuons)") + .Define("RecoMuon_py", "ReconstructedParticle::get_py(RecoMuons)") + .Define("RecoMuon_pz", "ReconstructedParticle::get_pz(RecoMuons)") + .Define("RecoMuon_charge", "ReconstructedParticle::get_charge(RecoMuons)") + + # finding the invariant mass of the reconstructed muon pair + .Define("Reco_mumu_energy", "if ((n_RecoMuons>1) && (RecoMuon_charge.at(0) != RecoMuon_charge.at(1))) return (RecoMuon_e.at(0) + RecoMuon_e.at(1)); else return float(-1.);") + .Define("Reco_mumu_px", "if ((n_RecoMuons>1) && (RecoMuon_charge.at(0) != RecoMuon_charge.at(1))) return (RecoMuon_px.at(0) + RecoMuon_px.at(1)); else return float(-1.);") + .Define("Reco_mumu_py", "if ((n_RecoMuons>1) && (RecoMuon_charge.at(0) != RecoMuon_charge.at(1))) return (RecoMuon_py.at(0) + RecoMuon_py.at(1)); else return float(-1.);") + .Define("Reco_mumu_pz", "if ((n_RecoMuons>1) && (RecoMuon_charge.at(0) != RecoMuon_charge.at(1))) return (RecoMuon_pz.at(0) + RecoMuon_pz.at(1)); else return float(-1.);") + .Define("Reco_mumu_invMass", "if ((n_RecoMuons>1) && (RecoMuon_charge.at(0) != RecoMuon_charge.at(1))) return sqrt(Reco_mumu_energy*Reco_mumu_energy - Reco_mumu_px*Reco_mumu_px - Reco_mumu_py*Reco_mumu_py - Reco_mumu_pz*Reco_mumu_pz ); else return float(-1.);") + + # Number of DVs with distance and invariant mass selection applied + .Define("filter_n_DVs_seltracks", "filter_n_DVs(Reco_seltracks_DVs_Lxyz, invMass_seltracks_DVs)") + .Define("filter_n_DVs_merge", "filter_n_DVs(Reco_DVs_merged_Lxyz, invMass_merged_DVs)") + + ) + return df2 + + + #__________________________________________________________ + #Mandatory: output function, please make sure you return the branchlist as a python list + def output(): + branchList = [ + "n_tracks", + "n_RecoedPrimaryTracks", + + 'n_seltracks_DVs', + 'n_trks_seltracks_DVs', + 'invMass_seltracks_DVs', + "DV_evt_seltracks_chi2", + "DV_evt_seltracks_normchi2", + "Reco_seltracks_DVs_Lxy", + "Reco_seltracks_DVs_Lxyz", + + "merged_DVs_n", + 'n_trks_merged_DVs', + 'invMass_merged_DVs', + "merged_DVs_chi2", + "merged_DVs_normchi2", + "Reco_DVs_merged_Lxy", + "Reco_DVs_merged_Lxyz", + + 'n_RecoElectrons', + "RecoElectron_e", + "RecoElectron_p", + "RecoElectron_pt", + "RecoElectron_px", + "RecoElectron_py", + "RecoElectron_pz", + "RecoElectron_charge", + "Reco_ee_invMass", + 'n_RecoMuons', + "RecoMuon_e", + "RecoMuon_p", + "RecoMuon_pt", + "RecoMuon_px", + "RecoMuon_py", + "RecoMuon_pz", + "RecoMuon_charge", + "Reco_mumu_invMass", + + "filter_n_DVs_seltracks", + "filter_n_DVs_merge", + ] + return branchList \ No newline at end of file