From f3c7d1d43d7f3cdf18002e10237b3db1f7ca8c52 Mon Sep 17 00:00:00 2001 From: Chriisbrown <41648127+Chriisbrown@users.noreply.github.com> Date: Mon, 26 Oct 2020 19:46:16 +0000 Subject: [PATCH] Track Quality Integration (#49) * Track Quality Integration * Track Ntuple Maker Max Events * PR Code Review Fixes #1 * Comments and style changes --- .../L1TrackTrigger/interface/TTTrack.h | 22 +- .../plugins/L1FPGATrackProducer.cc | 15 + .../python/Tracklet_cfi.py | 11 +- .../test/L1TrackNtupleMaker.cc | 17 + .../test/L1TrackNtupleMaker_cfg.py | 2 +- .../test/L1TrackNtuplePlot.C | 7 +- .../test/L1TrackQualityPlot.C | 680 ++++++++++++++++++ L1Trigger/TrackTrigger/BuildFile.xml | 1 + .../TrackTrigger/interface/TrackQuality.h | 75 ++ .../python/TrackQualityParams_cfi.py | 22 + L1Trigger/TrackTrigger/src/TrackQuality.cc | 249 +++++++ 11 files changed, 1095 insertions(+), 6 deletions(-) create mode 100644 L1Trigger/TrackFindingTracklet/test/L1TrackQualityPlot.C create mode 100644 L1Trigger/TrackTrigger/interface/TrackQuality.h create mode 100644 L1Trigger/TrackTrigger/python/TrackQualityParams_cfi.py create mode 100644 L1Trigger/TrackTrigger/src/TrackQuality.cc diff --git a/DataFormats/L1TrackTrigger/interface/TTTrack.h b/DataFormats/L1TrackTrigger/interface/TTTrack.h index afc30174a2468..8c57c0c287c1a 100644 --- a/DataFormats/L1TrackTrigger/interface/TTTrack.h +++ b/DataFormats/L1TrackTrigger/interface/TTTrack.h @@ -119,8 +119,11 @@ class TTTrack : public TTTrack_TrackWord { /// MVA Track quality variables double trkMVA1() const; + void settrkMVA1(double atrkMVA1); double trkMVA2() const; + void settrkMVA2(double atrkMVA2); double trkMVA3() const; + void settrkMVA3(double atrkMVA3); /// Phi Sector unsigned int phiSector() const { return thePhiSector_; } @@ -353,22 +356,39 @@ double TTTrack::chi2ZRed() const { return theChi2_Z_ / (theStubRefs.size() - 2.); } -/// MVA quality variables template double TTTrack::trkMVA1() const { return theTrkMVA1_; } +template +void TTTrack::settrkMVA1(double atrkMVA1) { + theTrkMVA1_ = atrkMVA1; + return; +} + template double TTTrack::trkMVA2() const { return theTrkMVA2_; } +template +void TTTrack::settrkMVA2(double atrkMVA2) { + theTrkMVA2_ = atrkMVA2; + return; +} + template double TTTrack::trkMVA3() const { return theTrkMVA3_; } +template +void TTTrack::settrkMVA3(double atrkMVA3) { + theTrkMVA3_ = atrkMVA3; + return; +} + /// StubPtConsistency template void TTTrack::setStubPtConsistency(double aStubPtConsistency) { diff --git a/L1Trigger/TrackFindingTracklet/plugins/L1FPGATrackProducer.cc b/L1Trigger/TrackFindingTracklet/plugins/L1FPGATrackProducer.cc index f468446048403..58c60199d39d2 100644 --- a/L1Trigger/TrackFindingTracklet/plugins/L1FPGATrackProducer.cc +++ b/L1Trigger/TrackFindingTracklet/plugins/L1FPGATrackProducer.cc @@ -93,6 +93,7 @@ #include "DataFormats/GeometrySurface/interface/BoundPlane.h" #include "L1Trigger/TrackTrigger/interface/StubPtConsistency.h" +#include "L1Trigger/TrackTrigger/interface/TrackQuality.h" ////////////// // STD HEADERS @@ -170,6 +171,10 @@ class L1FPGATrackProducer : public edm::one::EDProducer { unsigned int nHelixPar_; bool extended_; + bool trackQuality_; + edm::ParameterSet trackQualityParams; + std::unique_ptr trackQualityModel; + std::map> dtclayerdisk; edm::ESHandle tTopoHandle; @@ -286,6 +291,12 @@ L1FPGATrackProducer::L1FPGATrackProducer(edm::ParameterSet const& iConfig) << "\n table_TRE : " << tableTREFile.fullPath(); } } + + trackQuality_ = iConfig.getParameter("TrackQuality"); + if (trackQuality_) { + trackQualityParams = iConfig.getParameter("TrackQualityPSet"); + trackQualityModel.reset(new TrackQuality(trackQualityParams)); + } } ///////////// @@ -689,6 +700,10 @@ void L1FPGATrackProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSe // set TTTrack word aTrack.setTrackWordBits(); + if (trackQuality_) { + trackQualityModel->setTrackQuality(aTrack); + } + // test track word //aTrack.testTrackWordBits(); diff --git a/L1Trigger/TrackFindingTracklet/python/Tracklet_cfi.py b/L1Trigger/TrackFindingTracklet/python/Tracklet_cfi.py index 998ca97e35fed..9e03b4406b3c8 100644 --- a/L1Trigger/TrackFindingTracklet/python/Tracklet_cfi.py +++ b/L1Trigger/TrackFindingTracklet/python/Tracklet_cfi.py @@ -1,4 +1,5 @@ import FWCore.ParameterSet.Config as cms +from L1Trigger.TrackTrigger.TrackQualityParams_cfi import * TTTracksFromTrackletEmulation = cms.EDProducer("L1FPGATrackProducer", TTStubSource = cms.InputTag("TTStubsFromPhase2TrackerDigis","StubAccepted"), @@ -18,7 +19,10 @@ wiresFile = cms.FileInPath('L1Trigger/TrackFindingTracklet/data/wires_hourglass.dat'), DTCLinkFile = cms.FileInPath('L1Trigger/TrackFindingTracklet/data/calcNumDTCLinks.txt'), DTCLinkLayerDiskFile = cms.FileInPath('L1Trigger/TrackFindingTracklet/data/dtclinklayerdisk.dat'), - moduleCablingFile = cms.FileInPath('L1Trigger/TrackFindingTracklet/data/modules_T5v3_27SP_nonant_tracklet.dat') + moduleCablingFile = cms.FileInPath('L1Trigger/TrackFindingTracklet/data/modules_T5v3_27SP_nonant_tracklet.dat'), + # Quality Flag and Quality params + TrackQuality =cms.bool(False), + TrackQualityPSet = cms.PSet(TrackQualityParams) ) TTTracksFromExtendedTrackletEmulation = TTTracksFromTrackletEmulation.clone( @@ -29,6 +33,9 @@ wiresFile = cms.FileInPath('L1Trigger/TrackFindingTracklet/data/wires_hourglassExtended.dat'), # specifying where the TrackletEngineDisplaced(TED)/TripletEngine(TRE) tables are located tableTEDFile = cms.FileInPath('L1Trigger/TrackFindingTracklet/data/table_TED/table_TED_D1PHIA1_D2PHIA1.txt'), - tableTREFile = cms.FileInPath('L1Trigger/TrackFindingTracklet/data/table_TRE/table_TRE_D1AD2A_1.txt') + tableTREFile = cms.FileInPath('L1Trigger/TrackFindingTracklet/data/table_TRE/table_TRE_D1AD2A_1.txt'), + # Quality Flag and Quality params + TrackQuality =cms.bool(False), + TrackQualityPSet = cms.PSet(TrackQualityParams) ) diff --git a/L1Trigger/TrackFindingTracklet/test/L1TrackNtupleMaker.cc b/L1Trigger/TrackFindingTracklet/test/L1TrackNtupleMaker.cc index d86c90494b1e6..72fcd01eaf8d3 100644 --- a/L1Trigger/TrackFindingTracklet/test/L1TrackNtupleMaker.cc +++ b/L1Trigger/TrackFindingTracklet/test/L1TrackNtupleMaker.cc @@ -165,6 +165,7 @@ class L1TrackNtupleMaker : public edm::EDAnalyzer { std::vector* m_trk_unknown; std::vector* m_trk_combinatoric; std::vector* m_trk_fake; //0 fake, 1 track from primary interaction, 2 secondary track + std::vector* m_trk_MVA1; std::vector* m_trk_matchtp_pdgid; std::vector* m_trk_matchtp_pt; std::vector* m_trk_matchtp_eta; @@ -203,6 +204,7 @@ class L1TrackNtupleMaker : public edm::EDAnalyzer { std::vector* m_matchtrk_chi2rphi; std::vector* m_matchtrk_chi2rz; std::vector* m_matchtrk_bendchi2; + std::vector* m_matchtrk_MVA1; std::vector* m_matchtrk_nstub; std::vector* m_matchtrk_lhits; std::vector* m_matchtrk_dhits; @@ -331,6 +333,7 @@ void L1TrackNtupleMaker::beginJob() { m_trk_unknown = new std::vector; m_trk_combinatoric = new std::vector; m_trk_fake = new std::vector; + m_trk_MVA1 = new std::vector; m_trk_matchtp_pdgid = new std::vector; m_trk_matchtp_pt = new std::vector; m_trk_matchtp_eta = new std::vector; @@ -367,6 +370,7 @@ void L1TrackNtupleMaker::beginJob() { m_matchtrk_chi2rphi = new std::vector; m_matchtrk_chi2rz = new std::vector; m_matchtrk_bendchi2 = new std::vector; + m_matchtrk_MVA1 = new std::vector; m_matchtrk_nstub = new std::vector; m_matchtrk_dhits = new std::vector; m_matchtrk_lhits = new std::vector; @@ -426,6 +430,7 @@ void L1TrackNtupleMaker::beginJob() { eventTree->Branch("trk_unknown", &m_trk_unknown); eventTree->Branch("trk_combinatoric", &m_trk_combinatoric); eventTree->Branch("trk_fake", &m_trk_fake); + eventTree->Branch("trk_MVA1", &m_trk_MVA1); eventTree->Branch("trk_matchtp_pdgid", &m_trk_matchtp_pdgid); eventTree->Branch("trk_matchtp_pt", &m_trk_matchtp_pt); eventTree->Branch("trk_matchtp_eta", &m_trk_matchtp_eta); @@ -467,6 +472,7 @@ void L1TrackNtupleMaker::beginJob() { eventTree->Branch("matchtrk_chi2rphi", &m_matchtrk_chi2rphi); eventTree->Branch("matchtrk_chi2rz", &m_matchtrk_chi2rz); eventTree->Branch("matchtrk_bendchi2", &m_matchtrk_bendchi2); + eventTree->Branch("matchtrk_MVA1", &m_matchtrk_MVA1); eventTree->Branch("matchtrk_nstub", &m_matchtrk_nstub); eventTree->Branch("matchtrk_lhits", &m_matchtrk_lhits); eventTree->Branch("matchtrk_dhits", &m_matchtrk_dhits); @@ -550,6 +556,7 @@ void L1TrackNtupleMaker::analyze(const edm::Event& iEvent, const edm::EventSetup m_trk_unknown->clear(); m_trk_combinatoric->clear(); m_trk_fake->clear(); + m_trk_MVA1->clear(); m_trk_matchtp_pdgid->clear(); m_trk_matchtp_pt->clear(); m_trk_matchtp_eta->clear(); @@ -587,6 +594,7 @@ void L1TrackNtupleMaker::analyze(const edm::Event& iEvent, const edm::EventSetup m_matchtrk_chi2rphi->clear(); m_matchtrk_chi2rz->clear(); m_matchtrk_bendchi2->clear(); + m_matchtrk_MVA1->clear(); m_matchtrk_nstub->clear(); m_matchtrk_lhits->clear(); m_matchtrk_dhits->clear(); @@ -856,10 +864,15 @@ void L1TrackNtupleMaker::analyze(const edm::Event& iEvent, const edm::EventSetup tmp_trk_d0 = -tmp_trk_x0 * sin(tmp_trk_phi) + tmp_trk_y0 * cos(tmp_trk_phi); } + + + + float tmp_trk_chi2 = iterL1Track->chi2(); float tmp_trk_chi2rphi = iterL1Track->chi2XY(); float tmp_trk_chi2rz = iterL1Track->chi2Z(); float tmp_trk_bendchi2 = iterL1Track->stubPtConsistency(); + float tmp_trk_MVA1 = iterL1Track->trkMVA1(); std::vector >, TTStub > > stubRefs = iterL1Track->getStubRefs(); @@ -952,6 +965,7 @@ void L1TrackNtupleMaker::analyze(const edm::Event& iEvent, const edm::EventSetup m_trk_chi2rphi->push_back(tmp_trk_chi2rphi); m_trk_chi2rz->push_back(tmp_trk_chi2rz); m_trk_bendchi2->push_back(tmp_trk_bendchi2); + m_trk_MVA1->push_back(tmp_trk_MVA1); m_trk_nstub->push_back(tmp_trk_nstub); m_trk_dhits->push_back(tmp_trk_dhits); m_trk_lhits->push_back(tmp_trk_lhits); @@ -1320,6 +1334,7 @@ void L1TrackNtupleMaker::analyze(const edm::Event& iEvent, const edm::EventSetup float tmp_matchtrk_chi2rphi = -999; float tmp_matchtrk_chi2rz = -999; float tmp_matchtrk_bendchi2 = -999; + float tmp_matchtrk_MVA1 = -999; int tmp_matchtrk_nstub = -999; int tmp_matchtrk_dhits = -999; int tmp_matchtrk_lhits = -999; @@ -1345,6 +1360,7 @@ void L1TrackNtupleMaker::analyze(const edm::Event& iEvent, const edm::EventSetup tmp_matchtrk_chi2rphi = matchedTracks.at(i_track)->chi2XY(); tmp_matchtrk_chi2rz = matchedTracks.at(i_track)->chi2Z(); tmp_matchtrk_bendchi2 = matchedTracks.at(i_track)->stubPtConsistency(); + tmp_matchtrk_MVA1 = matchedTracks.at(i_track)->trkMVA1(); tmp_matchtrk_nstub = (int)matchedTracks.at(i_track)->getStubRefs().size(); tmp_matchtrk_seed = (int)matchedTracks.at(i_track)->trackSeedType(); tmp_matchtrk_hitpattern = (int)matchedTracks.at(i_track)->hitPattern(); @@ -1404,6 +1420,7 @@ void L1TrackNtupleMaker::analyze(const edm::Event& iEvent, const edm::EventSetup m_matchtrk_chi2rphi->push_back(tmp_matchtrk_chi2rphi); m_matchtrk_chi2rz->push_back(tmp_matchtrk_chi2rz); m_matchtrk_bendchi2->push_back(tmp_matchtrk_bendchi2); + m_matchtrk_MVA1->push_back(tmp_matchtrk_MVA1); m_matchtrk_nstub->push_back(tmp_matchtrk_nstub); m_matchtrk_dhits->push_back(tmp_matchtrk_dhits); m_matchtrk_lhits->push_back(tmp_matchtrk_lhits); diff --git a/L1Trigger/TrackFindingTracklet/test/L1TrackNtupleMaker_cfg.py b/L1Trigger/TrackFindingTracklet/test/L1TrackNtupleMaker_cfg.py index 35ca2308c8969..1891b1ff3e812 100644 --- a/L1Trigger/TrackFindingTracklet/test/L1TrackNtupleMaker_cfg.py +++ b/L1Trigger/TrackFindingTracklet/test/L1TrackNtupleMaker_cfg.py @@ -167,7 +167,7 @@ def getTxtFile(txtFileName): TrackingVertexInputTag = cms.InputTag("mix", "MergedTrackTruth"), # tracking in jets (--> requires AK4 genjet collection present!) TrackingInJets = cms.bool(False), - GenJetInputTag = cms.InputTag("ak4GenJets", ""), + GenJetInputTag = cms.InputTag("ak4GenJets", "") ) process.ana = cms.Path(process.L1TrackNtuple) diff --git a/L1Trigger/TrackFindingTracklet/test/L1TrackNtuplePlot.C b/L1Trigger/TrackFindingTracklet/test/L1TrackNtuplePlot.C index b3ab4660b0bd4..1da0f50363fc4 100644 --- a/L1Trigger/TrackFindingTracklet/test/L1TrackNtuplePlot.C +++ b/L1Trigger/TrackFindingTracklet/test/L1TrackNtuplePlot.C @@ -23,6 +23,7 @@ #include "TProfile2D.h" #include "TMath.h" #include +#include "TSystem.h" #include #include @@ -2021,7 +2022,8 @@ void L1TrackNtuplePlot(TString type, TH1F* h3_resVsEta_ptRel_L = new TH1F("resVsEta_ptRel_L_gaus", ";|#eta|; #sigma(p_{T}) / p_{T}", nETARANGE, 0, 2.4); TH1F* h3_resVsEta_ptRel_H = new TH1F("resVsEta_ptRel_H_gaus", ";|#eta|; #sigma(p_{T}) / p_{T}", nETARANGE, 0, 2.4); - + + gSystem->mkdir("FitResults"); TString fitdir = "FitResults/"; for (int i = 0; i < nETARANGE; i++) { @@ -2408,7 +2410,8 @@ void L1TrackNtuplePlot(TString type, char ctxt[500]; TCanvas c; - + + gSystem->mkdir("TrkPlots"); TString DIR = "TrkPlots/"; // plots overlaying 68, 90, 99% confidence levels] diff --git a/L1Trigger/TrackFindingTracklet/test/L1TrackQualityPlot.C b/L1Trigger/TrackFindingTracklet/test/L1TrackQualityPlot.C new file mode 100644 index 0000000000000..93ee874ffe95a --- /dev/null +++ b/L1Trigger/TrackFindingTracklet/test/L1TrackQualityPlot.C @@ -0,0 +1,680 @@ +// ---------------------------------------------------------------------------------------------------------------- +// Basic example ROOT script for making tracking performance plots using the ntuples produced by L1TrackNtupleMaker.cc +// +// e.g. in ROOT do: [0] .L L1TrackQualityPlot.C++ +// [1] L1TrackQualityPlot("TTbar_PU200_D49") +// +// By Claire Savard, July 2020 +// Based off of L1TrackNtuplePlot.C +// ---------------------------------------------------------------------------------------------------------------- + +#include "TROOT.h" +#include "TStyle.h" +#include "TLatex.h" +#include "TFile.h" +#include "TTree.h" +#include "TChain.h" +#include "TBranch.h" +#include "TLeaf.h" +#include "TCanvas.h" +#include "TLegend.h" +#include "TH1.h" +#include "TH2.h" +#include "TF1.h" +#include "TProfile.h" +#include "TProfile2D.h" +#include "TMath.h" +#include "TGraph.h" +#include "TError.h" +#include "TGraphErrors.h" +#include "TGraphPainter.h" +#include "TSystem.h" + +#include +#include +#include +#include +#include + +using namespace std; + +void SetPlotStyle(); + +// ---------------------------------------------------------------------------------------------------------------- +// Main script +// ---------------------------------------------------------------------------------------------------------------- + +void L1TrackQualityPlot(TString type, TString type_dir = "", TString treeName = "") { + // type: this is the name of the input file you want to process (minus ".root" extension) + // type_dir: this is the directory containing the input file you want to process. Note that this must end with a "/", as in "EventSets/" + + gROOT->SetBatch(); + gErrorIgnoreLevel = kWarning; + + SetPlotStyle(); + gSystem->mkdir("MVA_plots"); + + // ---------------------------------------------------------------------------------------------------------------- + // define input options + + // these are the LOOSE cuts, baseline scenario for efficiency and rate plots ==> configure as appropriate + int L1Tk_minNstub = 4; + float L1Tk_maxChi2 = 999999; + float L1Tk_maxChi2dof = 999999.; + + // ---------------------------------------------------------------------------------------------------------------- + // read ntuples + TChain* tree = new TChain("L1TrackNtuple" + treeName + "/eventTree"); + tree->Add(type_dir + type + ".root"); + + if (tree->GetEntries() == 0) { + cout << "File doesn't exist or is empty, returning..." + << endl; //cout's kept in this file as it is an example standalone plotting script, not running in central CMSSW + return; + } + + // ---------------------------------------------------------------------------------------------------------------- + // define leafs & branches + // all L1 tracks + vector* trk_pt; + vector* trk_eta; + vector* trk_phi; + vector* trk_chi2; + vector* trk_chi2rphi; + vector* trk_chi2rz; + vector* trk_nstub; + vector* trk_lhits; + vector* trk_dhits; + vector* trk_seed; + vector* trk_hitpattern; + vector* trk_phiSector; + vector* trk_fake; + vector* trk_genuine; + vector* trk_loose; + vector* trk_MVA1; + vector* trk_matchtp_pdgid; + + TBranch* b_trk_pt; + TBranch* b_trk_eta; + TBranch* b_trk_phi; + TBranch* b_trk_chi2; + TBranch* b_trk_chi2rphi; + TBranch* b_trk_chi2rz; + TBranch* b_trk_nstub; + TBranch* b_trk_lhits; + TBranch* b_trk_dhits; + TBranch* b_trk_phiSector; + TBranch* b_trk_seed; + TBranch* b_trk_hitpattern; + TBranch* b_trk_fake; + TBranch* b_trk_genuine; + TBranch* b_trk_loose; + TBranch* b_trk_MVA1; + TBranch* b_trk_matchtp_pdgid; + + trk_pt = 0; + trk_eta = 0; + trk_phi = 0; + trk_chi2 = 0; + trk_chi2rphi = 0; + trk_chi2rz = 0; + trk_nstub = 0; + trk_lhits = 0; + trk_dhits = 0; + trk_phiSector = 0; + trk_seed = 0; + trk_hitpattern = 0; + trk_fake = 0; + trk_genuine = 0; + trk_loose = 0; + trk_MVA1 = 0; + trk_matchtp_pdgid = 0; + + tree->SetBranchAddress("trk_pt", &trk_pt, &b_trk_pt); + tree->SetBranchAddress("trk_eta", &trk_eta, &b_trk_eta); + tree->SetBranchAddress("trk_phi", &trk_phi, &b_trk_phi); + tree->SetBranchAddress("trk_chi2", &trk_chi2, &b_trk_chi2); + tree->SetBranchAddress("trk_chi2rphi", &trk_chi2rphi, &b_trk_chi2rphi); + tree->SetBranchAddress("trk_chi2rz", &trk_chi2rz, &b_trk_chi2rz); + tree->SetBranchAddress("trk_nstub", &trk_nstub, &b_trk_nstub); + tree->SetBranchAddress("trk_lhits", &trk_lhits, &b_trk_lhits); + tree->SetBranchAddress("trk_dhits", &trk_dhits, &b_trk_dhits); + tree->SetBranchAddress("trk_phiSector", &trk_phiSector, &b_trk_phiSector); + tree->SetBranchAddress("trk_seed", &trk_seed, &b_trk_seed); + tree->SetBranchAddress("trk_hitpattern", &trk_hitpattern, &b_trk_hitpattern); + tree->SetBranchAddress("trk_fake", &trk_fake, &b_trk_fake); + tree->SetBranchAddress("trk_genuine", &trk_genuine, &b_trk_genuine); + tree->SetBranchAddress("trk_loose", &trk_loose, &b_trk_loose); + tree->SetBranchAddress("trk_MVA1", &trk_MVA1, &b_trk_MVA1); + tree->SetBranchAddress("trk_matchtp_pdgid", &trk_matchtp_pdgid, &b_trk_matchtp_pdgid); + + // ---------------------------------------------------------------------------------------------------------------- + // histograms + // ---------------------------------------------------------------------------------------------------------------- + + TH1F* h_trk_MVA1 = new TH1F("trk_MVA1", "; MVA1; L1 tracks", 50, 0, 1); + + TH1F* h_trk_MVA1_real = new TH1F("trk_MVA1_real", ";MVA1; L1 tracks", 50, 0, 1); + h_trk_MVA1_real->SetLineColor(3); + TH1F* h_trk_MVA1_fake = new TH1F("trk_MVA1_fake", ";MVA1; L1 tracks", 50, 0, 1); + h_trk_MVA1_fake->SetLineColor(4); + + // ---------------------------------------------------------------------------------------------------------------- + // * * * * * S T A R T O F A C T U A L R U N N I N G O N E V E N T S * * * * * + // ---------------------------------------------------------------------------------------------------------------- + + int nevt = tree->GetEntries(); + cout << "number of events = " << nevt << endl; + + // ---------------------------------------------------------------------------------------------------------------- + // event loop + vector MVA1s; + vector fakes; + vector etas; + vector pts; + vector pdgids; + for (int i = 0; i < nevt; i++) { + tree->GetEntry(i, 0); + + for (int it = 0; it < (int)trk_pt->size(); it++) { + // ---------------------------------------------------------------------------------------------------------------- + // track properties + + float MVA1 = trk_MVA1->at(it); + float fake = trk_fake->at(it); + float eta = trk_eta->at(it); + float pt = trk_pt->at(it); + float pdgid = trk_matchtp_pdgid->at(it); + + MVA1s.push_back(MVA1); + fakes.push_back(fake); + etas.push_back(eta); + pts.push_back(pt); + pdgids.push_back(pdgid); + + h_trk_MVA1->Fill(MVA1); + if (fake == 1.) + h_trk_MVA1_real->Fill(MVA1); + else if (fake == 0.) + h_trk_MVA1_fake->Fill(MVA1); + } + } + + // ------------------------------------------------------------------------------------------- + // create ROC curve + // ROC = Receiver Operating Characteristic Curve, a plot of True Positive Rate vs False Positive Rate + // TPR = True Positive Rate or Identification efficiency, fraction of real tracks correctly identified as real + // FPR = False Positive Rate or Fake Rate, fraction of fake tracks incorrectly identified as real + // dt = Decision Threshold or cut on the MVA output, below this identify track as fake, above identify as real + // ------------------------------------------------------------------------------------------- + + vector TPR, TPR_mu, TPR_el, TPR_had; + vector FPR; + vector dec_thresh; + int n = 100; //num of entries on ROC curve + for (int i = 0; i < n; i++) { + float dt = (float)i / (n - 1); //make sure it starts at (0,0) and ends at (1,1) + float TP = 0, TP_mu = 0, TP_el = 0, TP_had = 0; //True Positives + float FP = 0; //False Positives + float P = 0, P_mu = 0, P_el = 0, P_had = 0; //Total Positives + float N = 0; //Total Negatives + for (int k = 0; k < (int)MVA1s.size(); k++) { + if (fakes.at(k)) { + P++; + if (MVA1s.at(k) > dt) + TP++; + if (abs(pdgids.at(k)) == 13) { //muons + P_mu++; + if (MVA1s.at(k) > dt) + TP_mu++; + } else if (abs(pdgids.at(k)) == 11) { //electrons + P_el++; + if (MVA1s.at(k) > dt) + TP_el++; + } else if (abs(pdgids.at(k)) > 37 && abs(pdgids.at(k)) != 999) { //hadrons + P_had++; + if (MVA1s.at(k) > dt) + TP_had++; + } + } else { + N++; + if (MVA1s.at(k) > dt) + FP++; + } + } + TPR.push_back((float)TP / P); + TPR_mu.push_back((float)TP_mu / P_mu); + TPR_el.push_back((float)TP_el / P_el); + TPR_had.push_back((float)TP_had / P_had); + FPR.push_back((float)FP / N); + dec_thresh.push_back(dt); + } + + // calculate AUC (Area under the ROC curve) + float AUC = 0., AUC_mu = 0., AUC_el = 0., AUC_had = 0.; + for (int i = 0; i < n - 1; i++) { + AUC += (TPR[i] + TPR[i + 1]) / 2 * (FPR[i] - FPR[i + 1]); + AUC_mu += (TPR_mu[i] + TPR_mu[i + 1]) / 2 * (FPR[i] - FPR[i + 1]); + AUC_el += (TPR_el[i] + TPR_el[i + 1]) / 2 * (FPR[i] - FPR[i + 1]); + AUC_had += (TPR_had[i] + TPR_had[i + 1]) / 2 * (FPR[i] - FPR[i + 1]); + } + + TGraph* ROC = new TGraph(n, FPR.data(), TPR.data()); + ROC->SetName("ROC"); + ROC->SetTitle(("ROC curve (AUC = " + to_string(AUC) + "); FPR; TPR").c_str()); + ROC->SetLineWidth(4); + + TGraph* ROC_mu = new TGraph(n, FPR.data(), TPR_mu.data()); + ROC_mu->SetName("ROC_mu"); + ROC_mu->SetTitle(("ROC curve (muons, AUC = " + to_string(AUC_mu) + "); FPR; TPR").c_str()); + ROC_mu->SetLineWidth(4); + + TGraph* ROC_el = new TGraph(n, FPR.data(), TPR_el.data()); + ROC_el->SetName("ROC_el"); + ROC_el->SetTitle(("ROC curve (electrons, AUC = " + to_string(AUC_el) + "); FPR; TPR").c_str()); + ROC_el->SetLineWidth(4); + + TGraph* ROC_had = new TGraph(n, FPR.data(), TPR_had.data()); + ROC_had->SetName("ROC_had"); + ROC_had->SetTitle(("ROC curve (hadrons, AUC = " + to_string(AUC_had) + "); FPR; TPR").c_str()); + ROC_had->SetLineWidth(4); + + TGraph* TPR_vs_dt = new TGraph(n, dec_thresh.data(), TPR.data()); + TPR_vs_dt->SetName("TPR_vs_dt"); + TPR_vs_dt->SetTitle("TPR vs decision threshold; decision thresh.; TPR"); + TPR_vs_dt->SetLineColor(3); + TPR_vs_dt->SetLineWidth(4); + + TGraph* FPR_vs_dt = new TGraph(n, dec_thresh.data(), FPR.data()); + FPR_vs_dt->SetName("FPR_vs_dt"); + FPR_vs_dt->SetTitle("FPR vs decision threshold; decision thresh.; FPR"); + FPR_vs_dt->SetLineColor(4); + FPR_vs_dt->SetLineWidth(4); + + TGraph* TPR_vs_dt_mu = new TGraph(n, dec_thresh.data(), TPR_mu.data()); + TPR_vs_dt_mu->SetName("TPR_vs_dt_mu"); + TPR_vs_dt_mu->SetTitle("TPR vs decision threshold (muons); decision thresh.; TPR"); + TPR_vs_dt_mu->SetLineColor(3); + TPR_vs_dt_mu->SetLineWidth(4); + + TGraph* TPR_vs_dt_el = new TGraph(n, dec_thresh.data(), TPR_el.data()); + TPR_vs_dt_el->SetName("TPR_vs_dt_el"); + TPR_vs_dt_el->SetTitle("TPR vs decision threshold (electrons); decision thresh.; TPR"); + TPR_vs_dt_el->SetLineColor(3); + TPR_vs_dt_el->SetLineWidth(4); + + TGraph* TPR_vs_dt_had = new TGraph(n, dec_thresh.data(), TPR_had.data()); + TPR_vs_dt_had->SetName("TPR_vs_dt_had"); + TPR_vs_dt_had->SetTitle("TPR vs decision threshold (hadrons); decision thresh.; TPR"); + TPR_vs_dt_had->SetLineColor(3); + TPR_vs_dt_had->SetLineWidth(4); + + // ------------------------------------------------------------------------------------------- + // create TPR vs. eta and FPR vs. eta + // ------------------------------------------------------------------------------------------- + + vector TPR_eta, TPR_eta_mu, TPR_eta_el, TPR_eta_had; + vector TPR_eta_err, TPR_eta_err_mu, TPR_eta_err_el, TPR_eta_err_had; + vector FPR_eta, FPR_eta_err; + vector eta_range, eta_range_err; + n = 20; + float eta_low = -2.4; + float eta_high = 2.4; + float eta_temp = eta_low; + float eta_step = (eta_high - eta_low) / n; + float dt = .5; + for (int ct = 0; ct < n; ct++) { + float TP = 0, TP_mu = 0, TP_el = 0, TP_had = 0; + float FP = 0; + float P = 0, P_mu = 0, P_el = 0, P_had = 0; + float N = 0; + for (int k = 0; k < (int)etas.size(); k++) { + if (etas.at(k) > eta_temp && etas.at(k) <= (eta_temp + eta_step)) { + if (fakes.at(k)) { + P++; + if (MVA1s.at(k) > dt) + TP++; + if (abs(pdgids.at(k)) == 13) { //muons + P_mu++; + if (MVA1s.at(k) > dt) + TP_mu++; + } else if (abs(pdgids.at(k)) == 11) { //electrons + P_el++; + if (MVA1s.at(k) > dt) + TP_el++; + } else if (abs(pdgids.at(k)) > 37 && abs(pdgids.at(k)) != 999) { //hadrons + P_had++; + if (MVA1s.at(k) > dt) + TP_had++; + } + } else { + N++; + if (MVA1s.at(k) > dt) + FP++; + } + } + } + + //use min function to return 0 if no data filled + TPR_eta.push_back(min(TP / P, P)); + TPR_eta_mu.push_back(min(TP_mu / P_mu, P_mu)); + TPR_eta_el.push_back(min(TP_el / P_el, P_el)); + TPR_eta_had.push_back(min(TP_had / P_had, P_had)); + TPR_eta_err.push_back(min((float)sqrt(TP * (P - TP) / pow(P, 3)), P)); + TPR_eta_err_mu.push_back(min((float)sqrt(TP_mu * (P_mu - TP_mu) / pow(P_mu, 3)), P_mu)); + TPR_eta_err_el.push_back(min((float)sqrt(TP_mu * (P_el - TP_el) / pow(P_el, 3)), P_el)); + TPR_eta_err_had.push_back(min((float)sqrt(TP_had * (P_had - TP_had) / pow(P_had, 3)), P_had)); + + FPR_eta.push_back(min(FP / N, N)); + FPR_eta_err.push_back(min((float)sqrt(FP * (N - FP) / pow(N, 3)), N)); + + //fill eta range + eta_range.push_back(eta_temp + eta_step / 2); + eta_range_err.push_back(eta_step / 2); + + eta_temp += eta_step; + } + + TGraphErrors* TPR_vs_eta = + new TGraphErrors(n, eta_range.data(), TPR_eta.data(), eta_range_err.data(), TPR_eta_err.data()); + TPR_vs_eta->SetName("TPR_vs_eta"); + TPR_vs_eta->SetTitle("TPR vs. #eta; #eta; TPR"); + + TGraphErrors* FPR_vs_eta = + new TGraphErrors(n, eta_range.data(), FPR_eta.data(), eta_range_err.data(), FPR_eta_err.data()); + FPR_vs_eta->SetName("FPR_vs_eta"); + FPR_vs_eta->SetTitle("FPR vs. #eta; #eta; FPR"); + + TGraphErrors* TPR_vs_eta_mu = + new TGraphErrors(n, eta_range.data(), TPR_eta_mu.data(), eta_range_err.data(), TPR_eta_err_mu.data()); + TPR_vs_eta_mu->SetName("TPR_vs_eta_mu"); + TPR_vs_eta_mu->SetTitle("TPR vs. #eta (muons); #eta; TPR"); + + TGraphErrors* TPR_vs_eta_el = + new TGraphErrors(n, eta_range.data(), TPR_eta_el.data(), eta_range_err.data(), TPR_eta_err_el.data()); + TPR_vs_eta_el->SetName("TPR_vs_eta_el"); + TPR_vs_eta_el->SetTitle("TPR vs. #eta (electrons); #eta; TPR"); + + TGraphErrors* TPR_vs_eta_had = + new TGraphErrors(n, eta_range.data(), TPR_eta_had.data(), eta_range_err.data(), TPR_eta_err_had.data()); + TPR_vs_eta_had->SetName("TPR_vs_eta_had"); + TPR_vs_eta_had->SetTitle("TPR vs. #eta (hadrons); #eta; TPR"); + + // ------------------------------------------------------------------------------------------- + // create TPR vs. pt and FPR vs. pt + // ------------------------------------------------------------------------------------------- + + vector TPR_pt, TPR_pt_mu, TPR_pt_el, TPR_pt_had; + vector TPR_pt_err, TPR_pt_err_mu, TPR_pt_err_el, TPR_pt_err_had; + vector FPR_pt, FPR_pt_err; + vector pt_range, pt_range_err; + n = 10; + float logpt_low = log10(2); //set low pt in log + float logpt_high = log10(100); //set high pt in log + float logpt_temp = logpt_low; + float logpt_step = (logpt_high - logpt_low) / n; + dt = .5; + for (int ct = 0; ct < n; ct++) { + float TP = 0, TP_mu = 0, TP_el = 0, TP_had = 0; + float FP = 0; + float P = 0, P_mu = 0, P_el = 0, P_had = 0; + float N = 0; + for (int k = 0; k < (int)pts.size(); k++) { + if (pts.at(k) > pow(10, logpt_temp) && pts.at(k) <= (pow(10, logpt_temp + logpt_step))) { + if (fakes.at(k)) { + P++; + if (MVA1s.at(k) > dt) + TP++; + if (abs(pdgids.at(k)) == 13) { //muons + P_mu++; + if (MVA1s.at(k) > dt) + TP_mu++; + } else if (abs(pdgids.at(k)) == 11) { //electrons + P_el++; + if (MVA1s.at(k) > dt) + TP_el++; + } else if (abs(pdgids.at(k)) > 37 && abs(pdgids.at(k)) != 999) { //hadrons + P_had++; + if (MVA1s.at(k) > dt) + TP_had++; + } + } else { + N++; + if (MVA1s.at(k) > dt) + FP++; + } + } + } + + //use min function to return 0 if no data filled + TPR_pt.push_back(min(TP / P, P)); + TPR_pt_mu.push_back(min(TP_mu / P_mu, P_mu)); + TPR_pt_el.push_back(min(TP_el / P_el, P_el)); + TPR_pt_had.push_back(min(TP_had / P_had, P_had)); + TPR_pt_err.push_back(min((float)sqrt(TP * (P - TP) / pow(P, 3)), P)); + TPR_pt_err_mu.push_back(min((float)sqrt(TP_mu * (P_mu - TP_mu) / pow(P_mu, 3)), P_mu)); + TPR_pt_err_el.push_back(min((float)sqrt(TP_el * (P_el - TP_el) / pow(P_el, 3)), P_el)); + TPR_pt_err_had.push_back(min((float)sqrt(TP_had * (P_had - TP_had) / pow(P_had, 3)), P_had)); + + FPR_pt.push_back(min(FP / N, N)); + FPR_pt_err.push_back(min((float)sqrt(FP * (N - FP) / pow(N, 3)), N)); + + //fill pt range + pt_range.push_back((pow(10, logpt_temp) + pow(10, logpt_temp + logpt_step)) / 2); //halfway in bin + pt_range_err.push_back((pow(10, logpt_temp + logpt_step) - pow(10, logpt_temp)) / 2); + + logpt_temp += logpt_step; + } + + TGraphErrors* TPR_vs_pt = new TGraphErrors(n, pt_range.data(), TPR_pt.data(), pt_range_err.data(), TPR_pt_err.data()); + TPR_vs_pt->SetName("TPR_vs_pt"); + TPR_vs_pt->SetTitle("TPR vs. p_{T}; p_{T}; TPR"); + + TGraphErrors* FPR_vs_pt = new TGraphErrors(n, pt_range.data(), FPR_pt.data(), pt_range_err.data(), FPR_pt_err.data()); + FPR_vs_pt->SetName("FPR_vs_pt"); + FPR_vs_pt->SetTitle("FPR vs. p_{T}; p_{T}; FPR"); + + TGraphErrors* TPR_vs_pt_mu = + new TGraphErrors(n, pt_range.data(), TPR_pt_mu.data(), pt_range_err.data(), TPR_pt_err_mu.data()); + TPR_vs_pt_mu->SetName("TPR_vs_pt_mu"); + TPR_vs_pt_mu->SetTitle("TPR vs. p_{T} (muons); p_{T}; TPR"); + + TGraphErrors* TPR_vs_pt_el = + new TGraphErrors(n, pt_range.data(), TPR_pt_el.data(), pt_range_err.data(), TPR_pt_err_el.data()); + TPR_vs_pt_el->SetName("TPR_vs_pt_el"); + TPR_vs_pt_el->SetTitle("TPR vs. p_{T} (electrons); p_{T}; TPR"); + + TGraphErrors* TPR_vs_pt_had = + new TGraphErrors(n, pt_range.data(), TPR_pt_had.data(), pt_range_err.data(), TPR_pt_err_had.data()); + TPR_vs_pt_had->SetName("TPR_vs_pt_had"); + TPR_vs_pt_had->SetTitle("TPR vs. p_{T} (hadrons); p_{T}; TPR"); + + // ------------------------------------------------------------------------------------------- + // output file for histograms and graphs + // ------------------------------------------------------------------------------------------- + + TFile* fout = new TFile(type_dir + "MVAoutput_" + type + treeName + ".root", "recreate"); + TCanvas c; + + // ------------------------------------------------------------------------------------------- + // draw and save plots + // ------------------------------------------------------------------------------------------- + + h_trk_MVA1->Draw(); + h_trk_MVA1->Write(); + c.SaveAs("MVA_plots/trk_MVA.pdf"); + + h_trk_MVA1_real->Draw(); + h_trk_MVA1_fake->Draw("same"); + h_trk_MVA1_fake->SetTitle("Performance vs. decision threshold; decision thresh.; performance measure"); + TLegend* leg1 = new TLegend(); + leg1->AddEntry(h_trk_MVA1_real, "real", "l"); + leg1->AddEntry(h_trk_MVA1_fake, "fake", "l"); + leg1->Draw("same"); + c.Write("trk_MVA_rf"); + c.SaveAs("MVA_plots/trk_MVA_rf.pdf"); + + ROC->Draw("AL"); + ROC->Write(); + c.SaveAs("MVA_plots/ROC.pdf"); + + ROC_mu->Draw("AL"); + ROC_mu->Write(); + c.SaveAs("MVA_plots/ROC_mu.pdf"); + + ROC_el->Draw("AL"); + ROC_el->Write(); + c.SaveAs("MVA_plots/ROC_el.pdf"); + + ROC_had->Draw("AL"); + ROC_had->Write(); + c.SaveAs("MVA_plots/ROC_had.pdf"); + c.Clear(); + + TPR_vs_dt->Draw(); + FPR_vs_dt->Draw("same"); + TPR_vs_dt->SetTitle("Performance vs. decision threshold; decision thresh.; performance measure"); + TLegend* leg2 = new TLegend(); + leg2->AddEntry(TPR_vs_dt, "TPR", "l"); + leg2->AddEntry(FPR_vs_dt, "FPR", "l"); + leg2->Draw("same"); + c.Write("TPR_FPR_vs_dt"); + c.SaveAs("MVA_plots/TPR_FPR_vs_dt.pdf"); + c.Clear(); + + TPR_vs_dt_mu->Draw(); + FPR_vs_dt->Draw("same"); + TPR_vs_dt_mu->SetTitle("Performance vs. decision threshold (muons); decision thresh.; performance measure"); + TLegend* leg3 = new TLegend(); + leg3->AddEntry(TPR_vs_dt_mu, "TPR", "l"); + leg3->AddEntry(FPR_vs_dt, "FPR", "l"); + leg3->Draw("same"); + c.Write("TPR_FPR_vs_dt_mu"); + c.SaveAs("MVA_plots/TPR_FPR_vs_dt_mu.pdf"); + c.Clear(); + + TPR_vs_dt_el->Draw(); + FPR_vs_dt->Draw("same"); + TPR_vs_dt_el->SetTitle("Performance vs. decision threshold (electrons); decision thresh.; performance measure"); + TLegend* leg4 = new TLegend(); + leg4->AddEntry(TPR_vs_dt_el, "TPR", "l"); + leg4->AddEntry(FPR_vs_dt, "FPR", "l"); + leg4->Draw("same"); + c.Write("TPR_FPR_vs_dt_el"); + c.SaveAs("MVA_plots/TPR_FPR_vs_dt_el.pdf"); + c.Clear(); + + TPR_vs_dt_had->Draw(); + FPR_vs_dt->Draw("same"); + TPR_vs_dt_had->SetTitle("Performance vs. decision threshold (hadrons); decision thresh.; performance measure"); + TLegend* leg5 = new TLegend(); + leg5->AddEntry(TPR_vs_dt_had, "TPR", "l"); + leg5->AddEntry(FPR_vs_dt, "FPR", "l"); + leg5->Draw("same"); + c.Write("TPR_FPR_vs_dt_had"); + c.SaveAs("MVA_plots/TPR_FPR_vs_dt_had.pdf"); + c.Clear(); + + TPR_vs_eta->Draw("ap"); + TPR_vs_eta->Write(); + c.SaveAs("MVA_plots/TPR_vs_eta.pdf"); + + TPR_vs_eta_mu->Draw("ap"); + TPR_vs_eta_mu->Write(); + c.SaveAs("MVA_plots/TPR_vs_eta_mu.pdf"); + + TPR_vs_eta_el->Draw("ap"); + TPR_vs_eta_el->Write(); + c.SaveAs("MVA_plots/TPR_vs_eta_el.pdf"); + + TPR_vs_eta_had->Draw("ap"); + TPR_vs_eta_had->Write(); + c.SaveAs("MVA_plots/TPR_vs_eta_had.pdf"); + + FPR_vs_eta->Draw("ap"); + FPR_vs_eta->Write(); + c.SaveAs("MVA_plots/FPR_vs_eta.pdf"); + + TPR_vs_pt->Draw("ap"); + TPR_vs_pt->Write(); + c.SaveAs("MVA_plots/TPR_vs_pt.pdf"); + + TPR_vs_pt_mu->Draw("ap"); + TPR_vs_pt_mu->Write(); + c.SaveAs("MVA_plots/TPR_vs_pt_mu.pdf"); + + TPR_vs_pt_el->Draw("ap"); + TPR_vs_pt_el->Write(); + c.SaveAs("MVA_plots/TPR_vs_pt_el.pdf"); + + TPR_vs_pt_had->Draw("ap"); + TPR_vs_pt_had->Write(); + c.SaveAs("MVA_plots/TPR_vs_pt_had.pdf"); + + FPR_vs_pt->Draw("ap"); + FPR_vs_pt->Write(); + c.SaveAs("MVA_plots/FPR_vs_pt.pdf"); + + fout->Close(); +} + +void SetPlotStyle() { + // from ATLAS plot style macro + + // use plain black on white colors + gStyle->SetFrameBorderMode(0); + gStyle->SetFrameFillColor(0); + gStyle->SetCanvasBorderMode(0); + gStyle->SetCanvasColor(0); + gStyle->SetPadBorderMode(0); + gStyle->SetPadColor(0); + gStyle->SetStatColor(0); + gStyle->SetHistLineColor(1); + + gStyle->SetPalette(1); + + // set the paper & margin sizes + gStyle->SetPaperSize(20, 26); + gStyle->SetPadTopMargin(0.05); + gStyle->SetPadRightMargin(0.05); + gStyle->SetPadBottomMargin(0.16); + gStyle->SetPadLeftMargin(0.16); + + // set title offsets (for axis label) + gStyle->SetTitleXOffset(1.4); + gStyle->SetTitleYOffset(1.4); + + // use large fonts + gStyle->SetTextFont(42); + gStyle->SetTextSize(0.05); + gStyle->SetLabelFont(42, "x"); + gStyle->SetTitleFont(42, "x"); + gStyle->SetLabelFont(42, "y"); + gStyle->SetTitleFont(42, "y"); + gStyle->SetLabelFont(42, "z"); + gStyle->SetTitleFont(42, "z"); + gStyle->SetLabelSize(0.05, "x"); + gStyle->SetTitleSize(0.05, "x"); + gStyle->SetLabelSize(0.05, "y"); + gStyle->SetTitleSize(0.05, "y"); + gStyle->SetLabelSize(0.05, "z"); + gStyle->SetTitleSize(0.05, "z"); + + // use bold lines and markers + //gStyle->SetMarkerStyle(20); + gStyle->SetMarkerSize(1.2); + gStyle->SetHistLineWidth(4.); + gStyle->SetLineStyleString(4, "[12 12]"); + + // get rid of error bar caps + gStyle->SetEndErrorSize(0.); + + // do not display any of the standard histogram decorations + gStyle->SetOptTitle(0); + gStyle->SetOptStat(0); + gStyle->SetOptFit(0); + + // put tick marks on top and RHS of plots + gStyle->SetPadTickX(1); + gStyle->SetPadTickY(1); +} \ No newline at end of file diff --git a/L1Trigger/TrackTrigger/BuildFile.xml b/L1Trigger/TrackTrigger/BuildFile.xml index 0a83e6f47fcdb..65f7dde7a9ba9 100644 --- a/L1Trigger/TrackTrigger/BuildFile.xml +++ b/L1Trigger/TrackTrigger/BuildFile.xml @@ -12,6 +12,7 @@ + diff --git a/L1Trigger/TrackTrigger/interface/TrackQuality.h b/L1Trigger/TrackTrigger/interface/TrackQuality.h new file mode 100644 index 0000000000000..6d35f294145c4 --- /dev/null +++ b/L1Trigger/TrackTrigger/interface/TrackQuality.h @@ -0,0 +1,75 @@ +/* +Track Quality Header file + +C.Brown 28/07/20 +*/ + +#ifndef L1Trigger_TrackTrigger_interface_TrackQuality_h +#define L1Trigger_TrackTrigger_interface_TrackQuality_h + +#include +#include +#include +#include +#include + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/EDProducer.h" + +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/Framework/interface/ESHandle.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" + +#include "PhysicsTools/ONNXRuntime/interface/ONNXRuntime.h" + +#include "DataFormats/L1TrackTrigger/interface/TTTrack.h" +#include "DataFormats/L1TrackTrigger/interface/TTTypes.h" + +class TrackQuality { +public: + //Default Constructor + TrackQuality(); + + TrackQuality(edm::ParameterSet& qualityParams); + + //Default Destructor + ~TrackQuality() = default; + + // Controls the conversion between TTTrack features and ML model training features + std::vector featureTransform(TTTrack& aTrack, + std::vector const& featureNames); + + // Passed by reference a track without MVA filled, method fills the track's MVA field + void setTrackQuality(TTTrack& aTrack); + + // To set private member data + void setCutParameters(std::string const& qualityAlgorithm, + float maxZ0, + float maxEta, + float chi2dofMax, + float bendchi2Max, + float minPt, + int nStubmin); + + void setONNXModel(std::string const& qualityAlgorithm, + edm::FileInPath const& ONNXmodel, + std::string const& ONNXInputName, + std::vector const& featureNames); + +private: + // Private Member Data + std::string qualityAlgorithm_ = "None"; + edm::FileInPath ONNXmodel_; + std::string ONNXInputName_; + std::vector featureNames_; + float maxZ0_; + float maxEta_; + float chi2dofMax_; + float bendchi2Max_; + float minPt_; + int nStubsmin_; +}; +#endif diff --git a/L1Trigger/TrackTrigger/python/TrackQualityParams_cfi.py b/L1Trigger/TrackTrigger/python/TrackQualityParams_cfi.py new file mode 100644 index 0000000000000..de4338067a545 --- /dev/null +++ b/L1Trigger/TrackTrigger/python/TrackQualityParams_cfi.py @@ -0,0 +1,22 @@ +import FWCore.ParameterSet.Config as cms + +TrackQualityParams = cms.PSet(qualityAlgorithm = cms.string("GBDT"), #None, Cut, NN, GBDT + ONNXmodel = cms.string("L1Trigger/TrackTrigger/data/TrackQualityModels/GBDT_model.onnx"), + # !! TO BE UPDATED !! + # The ONNX model should be found at this path, if you want a local version of the model: + # git clone https://github.com/Chriisbrown/L1Trigger-TrackTrigger.git L1Trigger/TrackTrigger/data + ONNXInputName = cms.string("feature_input"), + #Vector of strings of training features, in the order that the model was trained with + featureNames = cms.vstring(["log_chi2","log_bendchi2","log_chi2rphi","log_chi2rz", + "nstubs","lay1_hits","lay2_hits","lay3_hits","lay4_hits", + "lay5_hits","lay6_hits","disk1_hits","disk2_hits", + "disk3_hits","disk4_hits","disk5_hits","rinv","tanl", + "z0","dtot","ltot"]), + # Parameters for cut based classifier, optimized for L1 Track MET + # (Table 3.7 The Phase-2 Upgrade of the CMS Level-1 Trigger http://cds.cern.ch/record/2714892) + maxZ0 = cms.double ( 15. ) , # in cm + maxEta = cms.double ( 2.4 ) , + chi2dofMax = cms.double( 40. ), + bendchi2Max = cms.double( 2.4 ), + minPt = cms.double( 2. ), # in GeV + nStubsmin = cms.int32( 4 )) diff --git a/L1Trigger/TrackTrigger/src/TrackQuality.cc b/L1Trigger/TrackTrigger/src/TrackQuality.cc new file mode 100644 index 0000000000000..6a81a2e992189 --- /dev/null +++ b/L1Trigger/TrackTrigger/src/TrackQuality.cc @@ -0,0 +1,249 @@ +/* +Track Quality Body file + +C.Brown & C.Savard 07/2020 +*/ + +#include "L1Trigger/TrackTrigger/interface/TrackQuality.h" + +//Constructors + +TrackQuality::TrackQuality() {} + +TrackQuality::TrackQuality(edm::ParameterSet& qualityParams) { + std::string qualityAlgorithm = qualityParams.getParameter("qualityAlgorithm"); + // Unpacks EDM parameter set itself to save unecessary processing within TrackProducers + if (qualityAlgorithm == "Cut") { + setCutParameters(qualityAlgorithm, + (float)qualityParams.getParameter("maxZ0"), + (float)qualityParams.getParameter("maxEta"), + (float)qualityParams.getParameter("chi2dofMax"), + (float)qualityParams.getParameter("bendchi2Max"), + (float)qualityParams.getParameter("minPt"), + qualityParams.getParameter("nStubsmin")); + } + + else { + setONNXModel(qualityAlgorithm, + edm::FileInPath(qualityParams.getParameter("ONNXmodel")), + qualityParams.getParameter("ONNXInputName"), + qualityParams.getParameter>("featureNames")); + } +} + +std::vector TrackQuality::featureTransform(TTTrack& aTrack, + std::vector const& featureNames) { + // List input features for MVA in proper order below, the features options are + // {"log_chi2","log_chi2rphi","log_chi2rz","log_bendchi2","nstubs","lay1_hits","lay2_hits", + // "lay3_hits","lay4_hits","lay5_hits","lay6_hits","disk1_hits","disk2_hits","disk3_hits", + // "disk4_hits","disk5_hits","rinv","tanl","z0","dtot","ltot","chi2","chi2rz","chi2rphi", + // "bendchi2","pt","eta","nlaymiss_interior"} + + std::vector transformedFeatures; + + // The following converts the 7 bit hitmask in the TTTrackword to an expected + // 11 bit hitmask based on the eta of the track + std::vector hitpattern_binary = {0, 0, 0, 0, 0, 0, 0}; + std::vector hitpattern_expanded_binary = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + std::vector eta_bins = {0.0, 0.2, 0.41, 0.62, 0.9, 1.26, 1.68, 2.08, 2.4}; + + // Expected hitmap table, each row corresponds to an eta bin, each value corresponds to + // the expected layer in the expanded hit pattern. The expanded hit pattern should be + // 11 bits but contains a 12th element so this hitmap table is symmetric + int hitmap[8][7] = {{0, 1, 2, 3, 4, 5, 11}, + {0, 1, 2, 3, 4, 5, 11}, + {0, 1, 2, 3, 4, 5, 11}, + {0, 1, 2, 3, 4, 5, 11}, + {0, 1, 2, 3, 4, 5, 11}, + {0, 1, 2, 6, 7, 8, 9}, + {0, 1, 7, 8, 9, 10, 11}, + {0, 6, 7, 8, 9, 10, 11}}; + + // iterate through bits of the hitpattern and compare to 1 filling the hitpattern binary vector + int tmp_trk_hitpattern = aTrack.hitPattern(); + for (int i = 6; i >= 0; i--) { + int k = tmp_trk_hitpattern >> i; + if (k & 1) + hitpattern_binary[i] = 1; + } + + // calculate number of missed interior layers from hitpattern + int nbits = floor(log2(tmp_trk_hitpattern)) + 1; + int lay_i = 0; + int tmp_trk_nlaymiss_interior = 0; + bool seq = false; + for (int i = 0; i < nbits; i++) { + lay_i = ((1 << i) & tmp_trk_hitpattern) >> i; //0 or 1 in ith bit (right to left) + + if (lay_i && !seq) + seq = true; //sequence starts when first 1 found + if (!lay_i && seq) + tmp_trk_nlaymiss_interior++; + } + + float eta = abs(aTrack.eta()); + int eta_size = static_cast(eta_bins.size()); + // First iterate through eta bins + + for (int j = 0; j < eta_size; j++) { + if (eta >= eta_bins[j] && eta < eta_bins[j + 1]) // if track in eta bin + { + // Iterate through hitpattern binary + for (int k = 0; k <= 6; k++) + // Fill expanded binary entries using the expected hitmap table positions + hitpattern_expanded_binary[hitmap[j][k]] = hitpattern_binary[k]; + } + } + + int tmp_trk_ltot = 0; + //calculate number of layer hits + for (int i = 0; i < 6; ++i) { + tmp_trk_ltot += hitpattern_expanded_binary[i]; + } + + int tmp_trk_dtot = 0; + //calculate number of disk hits + for (int i = 6; i < 11; ++i) { + tmp_trk_dtot += hitpattern_expanded_binary[i]; + } + + // While not strictly necessary to define these parameters, + // it is included so each variable is named to avoid confusion + float tmp_trk_big_invr = 500 * abs(aTrack.rInv()); + float tmp_trk_tanl = abs(aTrack.tanL()); + float tmp_trk_z0 = abs(aTrack.z0()); + float tmp_trk_pt = aTrack.momentum().perp(); + float tmp_trk_eta = aTrack.eta(); + float tmp_trk_chi2 = aTrack.chi2(); + float tmp_trk_chi2rphi = aTrack.chi2XY(); + float tmp_trk_chi2rz = aTrack.chi2Z(); + float tmp_trk_bendchi2 = aTrack.stubPtConsistency(); + float tmp_trk_log_chi2 = log(tmp_trk_chi2); + float tmp_trk_log_chi2rphi = log(tmp_trk_chi2rphi); + float tmp_trk_log_chi2rz = log(tmp_trk_chi2rz); + float tmp_trk_log_bendchi2 = log(tmp_trk_bendchi2); + + // fill feature map + std::map feature_map; + feature_map["log_chi2"] = tmp_trk_log_chi2; + feature_map["log_chi2rphi"] = tmp_trk_log_chi2rphi; + feature_map["log_chi2rz"] = tmp_trk_log_chi2rz; + feature_map["log_bendchi2"] = tmp_trk_log_bendchi2; + feature_map["chi2"] = tmp_trk_chi2; + feature_map["chi2rphi"] = tmp_trk_chi2rphi; + feature_map["chi2rz"] = tmp_trk_chi2rz; + feature_map["bendchi2"] = tmp_trk_bendchi2; + feature_map["nstubs"] = float(tmp_trk_dtot + tmp_trk_ltot); + feature_map["lay1_hits"] = float(hitpattern_expanded_binary[0]); + feature_map["lay2_hits"] = float(hitpattern_expanded_binary[1]); + feature_map["lay3_hits"] = float(hitpattern_expanded_binary[2]); + feature_map["lay4_hits"] = float(hitpattern_expanded_binary[3]); + feature_map["lay5_hits"] = float(hitpattern_expanded_binary[4]); + feature_map["lay6_hits"] = float(hitpattern_expanded_binary[5]); + feature_map["disk1_hits"] = float(hitpattern_expanded_binary[6]); + feature_map["disk2_hits"] = float(hitpattern_expanded_binary[7]); + feature_map["disk3_hits"] = float(hitpattern_expanded_binary[8]); + feature_map["disk4_hits"] = float(hitpattern_expanded_binary[9]); + feature_map["disk5_hits"] = float(hitpattern_expanded_binary[10]); + feature_map["rinv"] = tmp_trk_big_invr; + feature_map["tanl"] = tmp_trk_tanl; + feature_map["z0"] = tmp_trk_z0; + feature_map["dtot"] = float(tmp_trk_dtot); + feature_map["ltot"] = float(tmp_trk_ltot); + feature_map["pt"] = tmp_trk_pt; + feature_map["eta"] = tmp_trk_eta; + feature_map["nlaymiss_interior"] = float(tmp_trk_nlaymiss_interior); + + // fill tensor with track params + transformedFeatures.reserve(featureNames.size()); + for (const std::string& feature : featureNames) + transformedFeatures.push_back(feature_map[feature]); + + return transformedFeatures; +} + +void TrackQuality::setTrackQuality(TTTrack& aTrack) { + if (this->qualityAlgorithm_ == "Cut") { + // Get Track parameters + float trk_pt = aTrack.momentum().perp(); + float trk_bend_chi2 = aTrack.stubPtConsistency(); + float trk_z0 = aTrack.z0(); + float trk_eta = aTrack.momentum().eta(); + float trk_chi2 = aTrack.chi2(); + const auto& stubRefs = aTrack.getStubRefs(); + int nStubs = stubRefs.size(); + + float classification = 0.0; // Default classification is 0 + + if (trk_pt >= this->minPt_ && abs(trk_z0) < this->maxZ0_ && abs(trk_eta) < this->maxEta_ && + trk_chi2 < this->chi2dofMax_ && trk_bend_chi2 < this->bendchi2Max_ && nStubs >= this->nStubsmin_) + classification = 1.0; + // Classification updated to 1 if conditions are met + + aTrack.settrkMVA1(classification); + } + + if ((this->qualityAlgorithm_ == "NN") || (this->qualityAlgorithm_ == "GBDT")) { + // Setup ONNX input and output names and arrays + std::vector ortinput_names; + std::vector ortoutput_names; + + cms::Ort::FloatArrays ortinput; + cms::Ort::FloatArrays ortoutputs; + + std::vector Transformed_features = featureTransform(aTrack, this->featureNames_); + cms::Ort::ONNXRuntime Runtime(this->ONNXmodel_.fullPath()); //Setup ONNX runtime + + ortinput_names.push_back(this->ONNXInputName_); + ortoutput_names = Runtime.getOutputNames(); + + //ONNX runtime recieves a vector of vectors of floats so push back the input + // vector of float to create a 1,1,21 ortinput + ortinput.push_back(Transformed_features); + + // batch_size 1 as only one set of transformed features is being processed + int batch_size = 1; + // Run classification + ortoutputs = Runtime.run(ortinput_names, ortinput, {}, ortoutput_names, batch_size); + + if (this->qualityAlgorithm_ == "NN") { + aTrack.settrkMVA1(ortoutputs[0][0]); + } + + if (this->qualityAlgorithm_ == "GBDT") { + aTrack.settrkMVA1(ortoutputs[1][1]); + } + // Slight differences in the ONNX models of the GBDTs and NNs mean different + // indices of the ortoutput need to be accessed + } + + else { + aTrack.settrkMVA1(-999); + } +} + +void TrackQuality::setCutParameters(std::string const& qualityAlgorithm, + float maxZ0, + float maxEta, + float chi2dofMax, + float bendchi2Max, + float minPt, + int nStubmin) { + qualityAlgorithm_ = qualityAlgorithm; + maxZ0_ = maxZ0; + maxEta_ = maxEta; + chi2dofMax_ = chi2dofMax; + bendchi2Max_ = bendchi2Max; + minPt_ = minPt; + nStubsmin_ = nStubmin; +} + +void TrackQuality::setONNXModel(std::string const& qualityAlgorithm, + edm::FileInPath const& ONNXmodel, + std::string const& ONNXInputName, + std::vector const& featureNames) { + qualityAlgorithm_ = qualityAlgorithm; + ONNXmodel_ = ONNXmodel; + ONNXInputName_ = ONNXInputName; + featureNames_ = featureNames; +}