CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
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 
31  public:
35 
36  // virtual methods called from base class EDAnalyzer
37  virtual void beginJob() override;
38  virtual 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 
59  enum Flavour {
60  ALL_JETS = 0,
66  };
67 
68  TH1 *flavours_;
69 
70  // one group of plots per jet flavour;
71  struct Plots {
77 };
78 
80  jetsToken_(consumes<pat::JetCollection>(params.getParameter<edm::InputTag>("jets"))),
81  tracksToken_(consumes<reco::TrackCollection>(params.getParameter<edm::InputTag>("tracks"))),
82  beamSpotToken_(consumes<reco::BeamSpot>(params.getParameter<edm::InputTag>("beamSpot"))),
83  primaryVerticesToken_(consumes<reco::VertexCollection>(params.getParameter<edm::InputTag>("primaryVertices"))),
84  jetPtCut_(params.getParameter<double>("jetPtCut")),
85  jetEtaCut_(params.getParameter<double>("jetEtaCut")),
86  maxDeltaR_(params.getParameter<double>("maxDeltaR")),
87  minPt_(params.getParameter<double>("minPt")),
88  minPixelHits_(params.getParameter<unsigned int>("minPixelHits")),
89  minTotalHits_(params.getParameter<unsigned int>("minTotalHits")),
90  nThTrack_(params.getParameter<unsigned int>("nThTrack"))
91 {
92 }
93 
95 {
96 }
97 
99 {
100  // retrieve handle to auxiliary service
101  // used for storing histograms into ROOT file
103 
104  flavours_ = fs->make<TH1F>("flavours", "jet flavours", 5, 0, 5);
105 
106  // book histograms for all jet flavours
107  for(unsigned int i = 0; i < N_JET_TYPES; i++) {
108  Plots &plots = plots_[i];
109  const char *flavour, *name;
110 
111  switch((Flavour)i) {
112  case ALL_JETS:
113  flavour = "all jets";
114  name = "all";
115  break;
116  case UDSG_JETS:
117  flavour = "light flavour jets";
118  name = "udsg";
119  break;
120  case C_JETS:
121  flavour = "charm jets";
122  name = "c";
123  break;
124  case B_JETS:
125  flavour = "bottom jets";
126  name = "b";
127  break;
128  default:
129  flavour = "unidentified jets";
130  name = "ni";
131  break;
132  }
133 
134  plots.allIP = fs->make<TH1F>(Form("allIP_%s", name),
135  Form("signed IP for all tracks in %s", flavour),
136  100, -0.1, 0.2);
137  plots.allIPErr = fs->make<TH1F>(Form("allIPErr_%s", name),
138  Form("error of signed IP for all tracks in %s", flavour),
139  100, 0, 0.05);
140  plots.allIPSig = fs->make<TH1F>(Form("allIPSig_%s", name),
141  Form("signed IP significance for all tracks in %s", flavour),
142  100, -10, 20);
143 
144  plots.trackIP = fs->make<TH1F>(Form("trackIP_%s", name),
145  Form("signed IP for selected positive track in %s", flavour),
146  100, -0.1, 0.2);
147  plots.trackIPErr = fs->make<TH1F>(Form("trackIPErr_%s", name),
148  Form("error of signed IP for selected positive track in %s", flavour),
149  100, 0, 0.05);
150  plots.trackIPSig = fs->make<TH1F>(Form("trackIPSig_%s", name),
151  Form("signed IP significance for selected positive track in %s", flavour),
152  100, -10, 20);
153 
154  plots.negativeIP = fs->make<TH1F>(Form("negativeIP_%s", name),
155  Form("signed IP for selected negative track in %s", flavour),
156  100, -0.2, 0.1);
157  plots.negativeIPErr = fs->make<TH1F>(Form("negativeIPErr_%s", name),
158  Form("error of signed IP for selected negative track in %s", flavour),
159  100, 0, 0.05);
160  plots.negativeIPSig = fs->make<TH1F>(Form("negativeIPSig_%s", name),
161  Form("signed IP significance for selected negative track in %s", flavour),
162  100, -20, 10);
163 
164  plots.nTracks = fs->make<TH1F>(Form("nTracks_%s", name),
165  Form("number of usable tracks in %s", flavour),
166  30, 0, 30);
167  plots.allDeltaR = fs->make<TH1F>(Form("allDeltaR_%s", name),
168  Form("\\DeltaR between track and %s", flavour),
169  100, 0, 1);
170  }
171 }
172 
173 // helper function to sort the tracks by impact parameter significance
174 
175 static bool significanceHigher(const Measurement1D &meas1,
176  const Measurement1D &meas2)
177 { return meas1.significance() > meas2.significance(); }
178 
180 {
181  // handle to the primary vertex collection
183  event.getByToken(primaryVerticesToken_, pvHandle);
184 
185  // handle to the tracks collection
187  event.getByToken(tracksToken_, tracksHandle);
188 
189  // handle to the jets collection
191  event.getByToken(jetsToken_, jetsHandle);
192 
193  // handle to the beam spot
195  event.getByToken(beamSpotToken_, beamSpot);
196 
197  // rare case of no reconstructed primary vertex
198  if (pvHandle->empty())
199  return;
200 
201  // extract the position of the (most probable) reconstructed vertex
202  math::XYZPoint pv = (*pvHandle)[0].position();
203 
204  // now go through all jets
205  for(pat::JetCollection::const_iterator jet = jetsHandle->begin();
206  jet != jetsHandle->end(); ++jet) {
207 
208  // only look at jets that pass the pt and eta cut
209  if (jet->pt() < jetPtCut_ ||
210  std::abs(jet->eta()) > jetEtaCut_)
211  continue;
212 
214  // find out the jet flavour (differs between quark and anti-quark)
215  switch(std::abs(jet->partonFlavour())) {
216  case 1:
217  case 2:
218  case 3:
219  case 21:
220  flavour = UDSG_JETS;
221  break;
222  case 4:
223  flavour = C_JETS;
224  break;
225  case 5:
226  flavour = B_JETS;
227  break;
228  default:
229  flavour = NONID_JETS;
230  }
231 
232  // simply count the number of accepted jets
233  flavours_->Fill(ALL_JETS);
234  flavours_->Fill(flavour);
235 
236  // this vector will contain IP value / error pairs
237  std::vector<Measurement1D> ipValErr;
238 
239  // Note: PAT is also able to store associated tracks
240  // within the jet object, so we don't have to do the
241  // matching ourselves
242  // (see ->associatedTracks() method)
243  // However, using this we can't play with the DeltaR cone
244  // withour rerunning the PAT producer
245 
246  // now loop through all tracks
247  for(reco::TrackCollection::const_iterator track = tracksHandle->begin();
248  track != tracksHandle->end(); ++track) {
249 
250  // check the quality criteria
251  if (track->pt() < minPt_ ||
252  track->hitPattern().numberOfValidHits() < (int)minTotalHits_ ||
253  track->hitPattern().numberOfValidPixelHits() < (int)minPixelHits_)
254  continue;
255 
256  // check the Delta R between jet axis and track
257  // (Delta_R^2 = Delta_Eta^2 + Delta_Phi^2)
259  jet->momentum(), track->momentum());
260 
261  plots_[ALL_JETS].allDeltaR->Fill(deltaR);
262  plots_[flavour].allDeltaR->Fill(deltaR);
263 
264  // only look at tracks in jet cone
265  if (deltaR > maxDeltaR_)
266  continue;
267 
268  // What follows here is an approximation!
269  //
270  // The dxy() method of the tracks does a linear
271  // extrapolation from the track reference position
272  // given as the closest point to the beam spot
273  // with respect to the given vertex.
274  // Since we are using primary vertices, this
275  // approximation works well
276  //
277  // In order to get better results, the
278  // "TransientTrack" and specialised methods have
279  // to be used.
280  // Or look at the "impactParameterTagInfos",
281  // which contains the precomputed information
282  // from the official b-tagging algorithms
283  //
284  // see ->tagInfoTrackIP() method
285 
286  double ipError = track->dxyError();
287  double ipValue = std::abs(track->dxy(pv));
288 
289  // in order to compute the sign, we check if
290  // the point of closest approach to the vertex
291  // is in front or behind the vertex.
292  // Again, we a linear approximation
293  //
294  // dot product between reference point and jet axis
295 
296  math::XYZVector closestPoint = track->referencePoint() - beamSpot->position();
297  // only interested in transverse component, z -> 0
298  closestPoint.SetZ(0.);
299  double sign = closestPoint.Dot(jet->momentum());
300 
301  if (sign < 0)
302  ipValue = -ipValue;
303 
304  ipValErr.push_back(Measurement1D(ipValue, ipError));
305  }
306 
307  // now order all tracks by significance (highest first)
308  std::sort(ipValErr.begin(), ipValErr.end(), significanceHigher);
309 
310  plots_[ALL_JETS].nTracks->Fill(ipValErr.size());
311  plots_[flavour].nTracks->Fill(ipValErr.size());
312 
313  // plot all tracks
314 
315  for(std::vector<Measurement1D>::const_iterator iter = ipValErr.begin();
316  iter != ipValErr.end(); ++iter) {
317  plots_[ALL_JETS].allIP->Fill(iter->value());
318  plots_[flavour].allIP->Fill(iter->value());
319 
320  plots_[ALL_JETS].allIPErr->Fill(iter->error());
321  plots_[flavour].allIPErr->Fill(iter->error());
322 
323  // significance (is really just value / error)
324  plots_[ALL_JETS].allIPSig->Fill(iter->significance());
325  plots_[flavour].allIPSig->Fill(iter->significance());
326  }
327 
328  // check if we have enough tracks to fulfill the
329  // n-th track requirement
330  if (ipValErr.size() < nThTrack_)
331  continue;
332 
333  // pick the n-th highest track
334  const Measurement1D *trk = &ipValErr[nThTrack_ - 1];
335 
336  plots_[ALL_JETS].trackIP->Fill(trk->value());
337  plots_[flavour].trackIP->Fill(trk->value());
338 
339  plots_[ALL_JETS].trackIPErr->Fill(trk->error());
340  plots_[flavour].trackIPErr->Fill(trk->error());
341 
342  plots_[ALL_JETS].trackIPSig->Fill(trk->significance());
343  plots_[flavour].trackIPSig->Fill(trk->significance());
344 
345  // here we define a "negative tagger", i.e. we take
346  // the track with the n-lowest signed IP
347  // (i.e. preferrably select tracks that appear to become
348  // from "behind" the primary vertex, supposedly mismeasured
349  // tracks really coming from the primary vertex, and
350  // the contamination of displaced tracks should be small)
351  trk = &ipValErr[ipValErr.size() - nThTrack_];
352 
353  plots_[ALL_JETS].negativeIP->Fill(trk->value());
354  plots_[flavour].negativeIP->Fill(trk->value());
355 
356  plots_[ALL_JETS].negativeIPErr->Fill(trk->error());
357  plots_[flavour].negativeIPErr->Fill(trk->error());
358 
359  plots_[ALL_JETS].negativeIPSig->Fill(trk->significance());
360  plots_[flavour].negativeIPSig->Fill(trk->significance());
361  }
362 }
363 
365 
edm::EDGetTokenT< reco::TrackCollection > tracksToken_
int i
Definition: DBlmapReader.cc:9
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_
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:17
double sign(double x)
std::vector< Track > TrackCollection
collection of Tracks
Definition: TrackFwd.h:14
double error() const
Definition: Measurement1D.h:30
std::vector< Vertex > VertexCollection
collection of Vertex objects
Definition: VertexFwd.h:9
T * make(const Args &...args) const
make new ROOT object
Definition: TFileService.h:64
PatBJetTrackAnalyzer(const edm::ParameterSet &params)
constructor and destructor
virtual void beginJob() override
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
How EventSelector::AcceptEvent() decides whether to accept an event for output otherwise it is excluding the probing of A single or multiple positive and the trigger will pass if any such matching triggers are PASS or EXCEPTION[A criterion thatmatches no triggers at all is detected and causes a throw.] A single negative with an expectation of appropriate bit checking in the decision and the trigger will pass if any such matching triggers are FAIL or EXCEPTION A wildcarded negative criterion that matches more than one trigger in the trigger but the state exists so we define the behavior If all triggers are the negative crieriion will lead to accepting the event(this again matches the behavior of"!*"before the partial wildcard feature was incorporated).The per-event"cost"of each negative criterion with multiple relevant triggers is about the same as!*was in the past
double deltaR(double eta1, double eta2, double phi1, double phi2)
Definition: TreeUtility.cc:17
double significance() const
Definition: Measurement1D.h:32
XYZVectorD XYZVector
spatial vector with cartesian internal representation
Definition: Vector3D.h:30
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:28
virtual void analyze(const edm::Event &event, const edm::EventSetup &es) override
int flavour(const Candidate &part)
Definition: pdgIdUtils.h:31