CMS 3D CMS Logo

PatBJetTrackAnalyzer.cc
Go to the documentation of this file.
1 #include <algorithm>
2 #include <iostream>
3 #include <cmath>
4 #include <vector>
5 #include <string>
6 
7 #include <TH1.h>
8 #include <TProfile.h>
9 
10 #include <Math/VectorUtil.h>
11 
19 
21 
29 
30 class PatBJetTrackAnalyzer : public edm::one::EDAnalyzer<edm::one::SharedResources> {
31 public:
34  ~PatBJetTrackAnalyzer() override;
35 
36  // virtual methods called from base class EDAnalyzer
37  void beginJob() override;
38  void analyze(const edm::Event &event, const edm::EventSetup &es) override;
39 
40 private:
41  // configuration parameters
46 
47  double jetPtCut_; // minimum (uncorrected) jet energy
48  double jetEtaCut_; // maximum |eta| for jet
49  double maxDeltaR_; // angle between jet and tracks
50 
51  double minPt_; // track pt quality cut
52  unsigned int minPixelHits_; // minimum number of pixel hits
53  unsigned int minTotalHits_; // minimum number of total hits
54 
55  unsigned int nThTrack_; // n-th hightest track to choose
56 
57  // jet flavour constants
58 
60 
61  TH1 *flavours_;
62 
63  // one group of plots per jet flavour;
64  struct Plots {
70 };
71 
73  : jetsToken_(consumes<pat::JetCollection>(params.getParameter<edm::InputTag>("jets"))),
74  tracksToken_(consumes<reco::TrackCollection>(params.getParameter<edm::InputTag>("tracks"))),
75  beamSpotToken_(consumes<reco::BeamSpot>(params.getParameter<edm::InputTag>("beamSpot"))),
76  primaryVerticesToken_(consumes<reco::VertexCollection>(params.getParameter<edm::InputTag>("primaryVertices"))),
77  jetPtCut_(params.getParameter<double>("jetPtCut")),
78  jetEtaCut_(params.getParameter<double>("jetEtaCut")),
79  maxDeltaR_(params.getParameter<double>("maxDeltaR")),
80  minPt_(params.getParameter<double>("minPt")),
81  minPixelHits_(params.getParameter<unsigned int>("minPixelHits")),
82  minTotalHits_(params.getParameter<unsigned int>("minTotalHits")),
83  nThTrack_(params.getParameter<unsigned int>("nThTrack")) {
84  usesResource(TFileService::kSharedResource);
85 }
86 
88 
90  // retrieve handle to auxiliary service
91  // used for storing histograms into ROOT file
93 
94  flavours_ = fs->make<TH1F>("flavours", "jet flavours", 5, 0, 5);
95 
96  // book histograms for all jet flavours
97  for (unsigned int i = 0; i < N_JET_TYPES; i++) {
98  Plots &plots = plots_[i];
99  const char *flavour, *name;
100 
101  switch ((Flavour)i) {
102  case ALL_JETS:
103  flavour = "all jets";
104  name = "all";
105  break;
106  case UDSG_JETS:
107  flavour = "light flavour jets";
108  name = "udsg";
109  break;
110  case C_JETS:
111  flavour = "charm jets";
112  name = "c";
113  break;
114  case B_JETS:
115  flavour = "bottom jets";
116  name = "b";
117  break;
118  default:
119  flavour = "unidentified jets";
120  name = "ni";
121  break;
122  }
123 
124  plots.allIP =
125  fs->make<TH1F>(Form("allIP_%s", name), Form("signed IP for all tracks in %s", flavour), 100, -0.1, 0.2);
126  plots.allIPErr = fs->make<TH1F>(
127  Form("allIPErr_%s", name), Form("error of signed IP for all tracks in %s", flavour), 100, 0, 0.05);
128  plots.allIPSig = fs->make<TH1F>(
129  Form("allIPSig_%s", name), Form("signed IP significance for all tracks in %s", flavour), 100, -10, 20);
130 
131  plots.trackIP = fs->make<TH1F>(
132  Form("trackIP_%s", name), Form("signed IP for selected positive track in %s", flavour), 100, -0.1, 0.2);
133  plots.trackIPErr = fs->make<TH1F>(Form("trackIPErr_%s", name),
134  Form("error of signed IP for selected positive track in %s", flavour),
135  100,
136  0,
137  0.05);
138  plots.trackIPSig = fs->make<TH1F>(Form("trackIPSig_%s", name),
139  Form("signed IP significance for selected positive track in %s", flavour),
140  100,
141  -10,
142  20);
143 
144  plots.negativeIP = fs->make<TH1F>(
145  Form("negativeIP_%s", name), Form("signed IP for selected negative track in %s", flavour), 100, -0.2, 0.1);
146  plots.negativeIPErr = fs->make<TH1F>(Form("negativeIPErr_%s", name),
147  Form("error of signed IP for selected negative track in %s", flavour),
148  100,
149  0,
150  0.05);
151  plots.negativeIPSig = fs->make<TH1F>(Form("negativeIPSig_%s", name),
152  Form("signed IP significance for selected negative track in %s", flavour),
153  100,
154  -20,
155  10);
156 
157  plots.nTracks = fs->make<TH1F>(Form("nTracks_%s", name), Form("number of usable tracks in %s", flavour), 30, 0, 30);
158  plots.allDeltaR =
159  fs->make<TH1F>(Form("allDeltaR_%s", name), Form("\\DeltaR between track and %s", flavour), 100, 0, 1);
160  }
161 }
162 
163 // helper function to sort the tracks by impact parameter significance
164 
165 static bool significanceHigher(const Measurement1D &meas1, const Measurement1D &meas2) {
166  return meas1.significance() > meas2.significance();
167 }
168 
170  // handle to the primary vertex collection
172  event.getByToken(primaryVerticesToken_, pvHandle);
173 
174  // handle to the tracks collection
176  event.getByToken(tracksToken_, tracksHandle);
177 
178  // handle to the jets collection
180  event.getByToken(jetsToken_, jetsHandle);
181 
182  // handle to the beam spot
184  event.getByToken(beamSpotToken_, beamSpot);
185 
186  // rare case of no reconstructed primary vertex
187  if (pvHandle->empty())
188  return;
189 
190  // extract the position of the (most probable) reconstructed vertex
191  math::XYZPoint pv = (*pvHandle)[0].position();
192 
193  // now go through all jets
194  for (pat::JetCollection::const_iterator jet = jetsHandle->begin(); jet != jetsHandle->end(); ++jet) {
195  // only look at jets that pass the pt and eta cut
196  if (jet->pt() < jetPtCut_ || std::abs(jet->eta()) > jetEtaCut_)
197  continue;
198 
200  // find out the jet flavour (differs between quark and anti-quark)
201  switch (std::abs(jet->partonFlavour())) {
202  case 1:
203  case 2:
204  case 3:
205  case 21:
206  flavour = UDSG_JETS;
207  break;
208  case 4:
209  flavour = C_JETS;
210  break;
211  case 5:
212  flavour = B_JETS;
213  break;
214  default:
216  }
217 
218  // simply count the number of accepted jets
219  flavours_->Fill(ALL_JETS);
220  flavours_->Fill(flavour);
221 
222  // this vector will contain IP value / error pairs
223  std::vector<Measurement1D> ipValErr;
224 
225  // Note: PAT is also able to store associated tracks
226  // within the jet object, so we don't have to do the
227  // matching ourselves
228  // (see ->associatedTracks() method)
229  // However, using this we can't play with the DeltaR cone
230  // withour rerunning the PAT producer
231 
232  // now loop through all tracks
233  for (reco::TrackCollection::const_iterator track = tracksHandle->begin(); track != tracksHandle->end(); ++track) {
234  // check the quality criteria
235  if (track->pt() < minPt_ || track->hitPattern().numberOfValidHits() < (int)minTotalHits_ ||
236  track->hitPattern().numberOfValidPixelHits() < (int)minPixelHits_)
237  continue;
238 
239  // check the Delta R between jet axis and track
240  // (Delta_R^2 = Delta_Eta^2 + Delta_Phi^2)
241  double deltaR = ROOT::Math::VectorUtil::DeltaR(jet->momentum(), track->momentum());
242 
244  plots_[flavour].allDeltaR->Fill(deltaR);
245 
246  // only look at tracks in jet cone
247  if (deltaR > maxDeltaR_)
248  continue;
249 
250  // What follows here is an approximation!
251  //
252  // The dxy() method of the tracks does a linear
253  // extrapolation from the track reference position
254  // given as the closest point to the beam spot
255  // with respect to the given vertex.
256  // Since we are using primary vertices, this
257  // approximation works well
258  //
259  // In order to get better results, the
260  // "TransientTrack" and specialised methods have
261  // to be used.
262  // Or look at the "impactParameterTagInfos",
263  // which contains the precomputed information
264  // from the official b-tagging algorithms
265  //
266  // see ->tagInfoTrackIP() method
267 
268  double ipError = track->dxyError();
269  double ipValue = std::abs(track->dxy(pv));
270 
271  // in order to compute the sign, we check if
272  // the point of closest approach to the vertex
273  // is in front or behind the vertex.
274  // Again, we a linear approximation
275  //
276  // dot product between reference point and jet axis
277 
278  math::XYZVector closestPoint = track->referencePoint() - beamSpot->position();
279  // only interested in transverse component, z -> 0
280  closestPoint.SetZ(0.);
281  double sign = closestPoint.Dot(jet->momentum());
282 
283  if (sign < 0)
284  ipValue = -ipValue;
285 
286  ipValErr.push_back(Measurement1D(ipValue, ipError));
287  }
288 
289  // now order all tracks by significance (highest first)
290  std::sort(ipValErr.begin(), ipValErr.end(), significanceHigher);
291 
292  plots_[ALL_JETS].nTracks->Fill(ipValErr.size());
293  plots_[flavour].nTracks->Fill(ipValErr.size());
294 
295  // plot all tracks
296 
297  for (std::vector<Measurement1D>::const_iterator iter = ipValErr.begin(); iter != ipValErr.end(); ++iter) {
298  plots_[ALL_JETS].allIP->Fill(iter->value());
299  plots_[flavour].allIP->Fill(iter->value());
300 
301  plots_[ALL_JETS].allIPErr->Fill(iter->error());
302  plots_[flavour].allIPErr->Fill(iter->error());
303 
304  // significance (is really just value / error)
305  plots_[ALL_JETS].allIPSig->Fill(iter->significance());
306  plots_[flavour].allIPSig->Fill(iter->significance());
307  }
308 
309  // check if we have enough tracks to fulfill the
310  // n-th track requirement
311  if (ipValErr.size() < nThTrack_)
312  continue;
313 
314  // pick the n-th highest track
315  const Measurement1D *trk = &ipValErr[nThTrack_ - 1];
316 
317  plots_[ALL_JETS].trackIP->Fill(trk->value());
318  plots_[flavour].trackIP->Fill(trk->value());
319 
320  plots_[ALL_JETS].trackIPErr->Fill(trk->error());
321  plots_[flavour].trackIPErr->Fill(trk->error());
322 
323  plots_[ALL_JETS].trackIPSig->Fill(trk->significance());
324  plots_[flavour].trackIPSig->Fill(trk->significance());
325 
326  // here we define a "negative tagger", i.e. we take
327  // the track with the n-lowest signed IP
328  // (i.e. preferrably select tracks that appear to become
329  // from "behind" the primary vertex, supposedly mismeasured
330  // tracks really coming from the primary vertex, and
331  // the contamination of displaced tracks should be small)
332  trk = &ipValErr[ipValErr.size() - nThTrack_];
333 
334  plots_[ALL_JETS].negativeIP->Fill(trk->value());
335  plots_[flavour].negativeIP->Fill(trk->value());
336 
337  plots_[ALL_JETS].negativeIPErr->Fill(trk->error());
338  plots_[flavour].negativeIPErr->Fill(trk->error());
339 
340  plots_[ALL_JETS].negativeIPSig->Fill(trk->significance());
341  plots_[flavour].negativeIPSig->Fill(trk->significance());
342  }
343 }
344 
346 
static const std::string kSharedResource
Definition: TFileService.h:76
edm::EDGetTokenT< reco::TrackCollection > tracksToken_
edm::EDGetTokenT< reco::VertexCollection > primaryVerticesToken_
std::vector< Jet > JetCollection
Definition: Jet.h:53
static bool significanceHigher(const Measurement1D &meas1, const Measurement1D &meas2)
edm::EDGetTokenT< pat::JetCollection > jetsToken_
std::vector< Track > TrackCollection
collection of Tracks
Definition: TrackFwd.h:14
PatBJetTrackAnalyzer(const edm::ParameterSet &params)
constructor and destructor
std::vector< Vertex > VertexCollection
Definition: Vertex.h:31
Definition: HeavyIon.h:7
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
XYZVectorD XYZVector
spatial vector with cartesian internal representation
Definition: Vector3D.h:31
XYZPointD XYZPoint
point in space with cartesian internal representation
Definition: Point3D.h:12
struct PatBJetTrackAnalyzer::Plots plots_[N_JET_TYPES]
edm::EDGetTokenT< reco::BeamSpot > beamSpotToken_
double value() const
Definition: Measurement1D.h:25
void analyze(const edm::Event &event, const edm::EventSetup &es) override
double significance() const
Definition: Measurement1D.h:29
fixed size matrix
HLT enums.
double error() const
Definition: Measurement1D.h:27
Definition: event.py:1